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

    在日常使用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;
    }

    再次运行程序,没有问题

  • 相关阅读:
    5种Python使用定时调度任务的方式
    基于Tensorflow + Opencv 实现CNN自定义图像分类
    CANN 5.0硬核技术抢先看
    大力出奇迹,揭秘昇腾CANN的AI超能力
    MSQL:超强的多任务表示学习方法
    Shell:Lite OS在线调试工具知多少
    带你掌握Vue过滤器filters及时间戳转换
    Selenium系列(六) 详细解读强制等待、隐式等待、显式等待的区别和源码解读
    Linux常用命令 top命令详解(重点)
    Selenium系列(一) 详细解读8种元素定位方式
  • 原文地址:https://www.cnblogs.com/godbell/p/7360739.html
Copyright © 2011-2022 走看看