您的位置:首页 > 其它

关于Entity Framework更新的几种方式以及可能遇到的问题(附加类型“Model”的实体失败,因为相同类型的其他实体已具有相同的主键值)在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为

2017-08-14 22:59 1451 查看
在日常使用Entity Framework中,数据更新通常会用到。下面就简单封装了一个DBContext类

public partial class EFContext<T> : DbContext where T : class
{
public EFContext(): base("name=MyConnectionString")
{
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<EFContext<T>> (null);
modelBuilder.Configurations.Add(new MemberMap());
modelBuilder.Configurations.Add(new RoleMap());
base.OnModelCreating(modelBuilder);
}

public DbSet<T> Table { get; set; }

public IQueryable<T> GetList(Expression<Func<T,bool>> where)
{
return this.Table.Where(where);
}

public void Update(T entity)
{
if (entity == null)
{
throw new ArgumentException("entity");
}
this.SaveChanges();
}
}


View Code
第一种更新方式,先通过Entity Framework从数据库中查找出一条记录(实体对象),然后修改实体对象的各个属性,最后调用Update方法

static void Main(string[] args)
{
EFContext<Member> memberContext = new EFContext<Member>();
var members = memberContext.GetList(m => true).ToList();
var model = members.Find(m => m.Id == 3);

//第一种更新方式
model.Name = "猪八戒";
model.Delete = false;
memberContext.Update(model);
Console.ReadKey();
}


运行程序前:



运行程序后:



上面的方式可以修改为下面方式,DbContext封装类中Update可以修改为如下的形式:

public void Update(T entity)
{
if (entity == null)
{
throw new ArgumentException("entity");
}
this.Table.Attach(entity);
this.Entry(entity).State = EntityState.Modified;
this.SaveChanges();
}


static void Main(string[] args)
{
EFContext<Member> memberContext = new EFContext<Member>();
var members = memberContext.GetList(m => true).ToList();
var model = members.Find(m => m.Id == 3);

//第一种更新方式
model.Name = "沙师弟";
model.Delete = true;
memberContext.Update(model);
Console.ReadKey();
}


运行前:



运行后:



第二种方式是new一个对象,这个对象各个属性赋值,主键Id与数据库某条已存在的记录的Id相同

static void Main(string[] args)
{
EFContext<Member> memberContext = new EFContext<Member>();
var members = memberContext.GetList(m => true).ToList();
//var model = members.Find(m => m.Id == 3);

////第一种更新方式
//model.Name = "沙师弟";
//model.Delete = true;
//memberContext.Update(model);

//第二种方式
Member entity = new Member();
entity.Id = 3;
entity.Name = "李小龙";
entity.Password = "lixiaolong";
entity.Delete = false;
entity.RoleId = 3;
memberContext.Update(entity);

Console.WriteLine("update complete.");
Console.ReadKey();
}


运行程序,会抛出异常。



附加类型“Core.Member”的实体失败,因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为。这可能是因为某些实体是新的并且尚未接收数据库生成的键值。在此情况下,使用 "Add" 方法或者 "Added" 实体状态跟踪该图形,然后将非新实体的状态相应设置为 "Unchanged" 或 "Modified"。

因为Attach的实体对象是通过new创建的,而不是通过Entity Framework从数据库中获取的,但实例的主键对应数据在数据库中存在,该实例而不存在于DBContext上下文中,尝试Attach会抛出异常。通过监视可以看到是未附加到DbContext中



修改Update方法如下:

public void Update(T entity)
{
if (entity == null)
{
throw new ArgumentException("entity");
}
if (this.Entry(entity).State == EntityState.Detached)
{
HandleDetached(entity);
}
this.Table.Attach(entity);
this.Entry(entity).State = EntityState.Modified;
this.SaveChanges();
}

private bool HandleDetached(T entity)
{
var objectContext = ((IObjectContextAdapter)this).ObjectContext;
var entitySet = objectContext.CreateObjectSet<T>();
var entityKey = objectContext.CreateEntityKey(entitySet.EntitySet.Name, entity);
object foundSet;
bool exists = objectContext.TryGetObjectByKey(entityKey, out foundSet);
if (exists)
{
objectContext.Detach(foundSet); //从上下文中移除
}
return exists;
}


再次运行程序,没有问题

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐