关于Entity Framework更新的几种方式以及可能遇到的问题(附加类型“Model”的实体失败,因为相同类型的其他实体已具有相同的主键值)在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为
2017-08-14 22:59
1451 查看
在日常使用Entity Framework中,数据更新通常会用到。下面就简单封装了一个DBContext类
View Code
第一种更新方式,先通过Entity Framework从数据库中查找出一条记录(实体对象),然后修改实体对象的各个属性,最后调用Update方法
运行程序前:
运行程序后:
上面的方式可以修改为下面方式,DbContext封装类中Update可以修改为如下的形式:
运行前:
运行后:
第二种方式是new一个对象,这个对象各个属性赋值,主键Id与数据库某条已存在的记录的Id相同
运行程序,会抛出异常。
附加类型“Core.Member”的实体失败,因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为。这可能是因为某些实体是新的并且尚未接收数据库生成的键值。在此情况下,使用 "Add" 方法或者 "Added" 实体状态跟踪该图形,然后将非新实体的状态相应设置为 "Unchanged" 或 "Modified"。
因为Attach的实体对象是通过new创建的,而不是通过Entity Framework从数据库中获取的,但实例的主键对应数据在数据库中存在,该实例而不存在于DBContext上下文中,尝试Attach会抛出异常。通过监视可以看到是未附加到DbContext中
修改Update方法如下:
再次运行程序,没有问题
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; }
再次运行程序,没有问题
相关文章推荐
- 附加类型“UniversalReviewSystem.Models.ApplicationUser”的实体失败,因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值
- 因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 。。。
- 错误:因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 解决方法
- 一例附加类型“LMSoft.FrameWork.Identity.ApplicationUser”的实体失败,因为相同类型的其他实体已具有相同的主键值错误的解决
- EF 中更新模型的问题,这种错误(因为相同类型的其他实体已具有相同的主键值。)
- DLINQ 使用DataContext快速构建数据访问层DAL,发现Updata采用Attach(Entity t,true)困难重重!(如果实体声明了版本成员或者没有更新检查策略,则只能将它附加为没有原始状态的已修改实体)的解决办法!
- 解决 ”不允许在查询中显式构造实体类型“问题及使用其他方法实现返回 List<Model对象>或者IQueryable<Model对象>对象
- 关于“打开项目**时发生问题,尝试退出并重新启动应用程序。如果问题仍然存在,则可能是由于正在使用不支持的项目版本,或者项目文件可能损坏”的问题的解决办法。
- EF(Entity Framework)发生错误”正在创建模型,此时不可使用上下文“的解决办法。 正在创建模型,此时不可使用上下文。如果在 OnModelCreating 方法内使用上下文或如果多个线程同时访问同一上下文实例,可能引发此异常。请注意不保证 DbContext 的实例成员和相关类是线程安全的。 临时解决了这个问题,在Context的构造函数中,禁用了自动初始化:
- EF5+MVC4系列(5) 删除的方法 1:系统推荐的先查询后remove删除的方法 2:自己new一个包含主键的类,然后 attach附加 remove删除;3:使用db.Entry 修改状态删除4:EntityState的几种状态
- 关于火狐游览器设置全屏状态不显示工具栏以及其他游览器全屏问题
- 生产环境使用elasticsearch遇到的一些问题以及解决方法(不断更新)
- 使用CentOS 遇到的问题以及解决方法(持续更新)
- 关于Resin在Eclipse或者Myeclipse上利用Debug模式部署的方法以及遇到的一些问题
- 使用mybatis遇到的关于条件查询">"以及if test传参的使用问题
- 生产环境使用elasticsearch遇到的一些问题以及解决方法(不断更新)
- 关于"作数类型冲突: nvarchar 与 image 不兼容"的问题(DBNull)
- 关于ArrayList使用时常遇到的问题以及解决方法
- 关于在用curl函数post网页数据时,遇上表单提交 type为submit 类型而且没有name和id时可能遇到的问题及其解决方法
- 遇到“拒绝了对对象的 EXECUTE 权限”和“无法作为数据库主体执行,因为主体 "dbo" 不存在、无法模拟这种类型的主体,或您没有所需的权限”的问题