在日常使用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();
}
}
第一种更新方式,先通过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 == ); //第一种更新方式
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 == ); //第一种更新方式
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 = ;
entity.Name = "李小龙";
entity.Password = "lixiaolong";
entity.Delete = false;
entity.RoleId = ;
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;
}
再次运行程序,没有问题