【问题标题】:EF Code First Detached Entity not updating object referenceEF Code First Detached Entity 不更新对象引用
【发布时间】:2012-11-13 17:14:21
【问题描述】:

我正在发布确切的实体:

    public class Person : ContactableEntity
{

    public Plan Plan { get; set; }

    public int Record { get; set; }

    public int PersonTypeValue { get; set; }

}

我正在使用以下代码以不相关的上下文方式进行更新:

        public void Update(DbSet MySet, object Obj)
    {
        MySet.Attach(Obj);
        var Entry = this.Entry(Obj);
        Entry.State = EntityState.Modified;
        this.SaveChanges();
    }

这是我的 dbContext 公开的方法 这样称呼:

PersistentManager.Update(PersistentManager.Personas,UpdatedPersona);

问题是,EF 将更新除引用的 Plan 对象之外的任何属性。 有人可以告诉我错误在哪里吗? 提前:实体到达更新点并正确设置所有属性。 EF 只是无法更新数据库中的 FK(但也不例外) 更新: 尝试解决这样的问题,但没有奏效:

            PersistentMgr.Contacts.Attach(Obj);
            PersistentMgr.Entry(Obj).State = EntityState.Modified;
            PersistentMgr.Entry(Obj.Plan).State = EntityState.Modified;
            PersistentMgr.SaveChanges();

【问题讨论】:

    标签: entity-framework ef-code-first stateless


    【解决方案1】:

    你需要...

    this.Entry(person).State = EntityState.Modified;
    this.Entry(person.Plan).State = EntityState.Modified;
    

    ...因为当您将person 的状态设置为Modified 时,此人会以Modified 状态连接到上下文,但像person.Plan 这样的相关实体会以Unchanged 状态连接。

    如果PersonPlan 之间的关系在实体分离时发生了变化,则更难(尤其是在您的模型中,当没有外键作为属性(“独立关联”)公开时)正确更新实体。您基本上需要从数据库中加载原始对象图,如果关系已更改,则将其与分离图进行比较,然后将更改合并到加载的图中。一个例子是here(参见该答案中的第二个代码 sn-p)。

    编辑

    显示它有效的示例(使用 EF 5.0):

    using System.Data;
    using System.Data.Entity;
    using System.Linq;
    
    namespace EFModifyTest
    {
        public class Person
        {
            public int Id { get; set; }
            public Plan Plan { get; set; }
            public int Record { get; set; }
            public int PersonTypeValue { get; set; }
        }
    
        public class Plan
        {
            public int Id { get; set; }
            public string SomeText { get; set; }
        }
    
        public class MyContext : DbContext
        {
            public DbSet<Person> Contacts { get; set; }
            public DbSet<Plan> Plans { get; set; }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
    
                // Create a person with plan
                using (var ctx = new MyContext())
                {
                    ctx.Database.Initialize(true);
    
                    var plan = new Plan { SomeText = "Old Text" };
                    var person = new Person { Plan = plan, Record = 1, PersonTypeValue = 11 };
    
                    ctx.Contacts.Add(person);
    
                    ctx.SaveChanges();
                }
                // see screenshot 1 from SQL Server Management Studio
    
                Person detachedPerson = null;
                // Load the person with plan
                using (var ctx = new MyContext())
                {
                    detachedPerson = ctx.Contacts.Include(c => c.Plan).First();
                }
    
                // Modify person and plan while they are detached
                detachedPerson.Record = 2;
                detachedPerson.PersonTypeValue = 12;
                detachedPerson.Plan.SomeText = "New Text";
    
                // Attach person and plan to new context and set their states to Modified
                using (var ctx = new MyContext())
                {
                    ctx.Entry(detachedPerson).State = EntityState.Modified;
                    ctx.Entry(detachedPerson.Plan).State = EntityState.Modified;
    
                    ctx.SaveChanges();
                }
                // see screenshot 2 from SQL Server Management Studio
            }
        }
    }
    

    来自 SQL Server Management Studio 的屏幕截图 1(修改前,Person 表在左侧,Plan 表在右侧):

    来自 SQL Server Management Studio 的屏幕截图 2(修改后,Person 表在左侧,Plan 表在右侧):

    如果它对您不起作用,那么我的测试模型和代码一定有重要的不同。我不知道是哪一个,你必须提供更多的细节。

    编辑 2

    如果您将关系从 Person 更改为另一个(现有)Plan,则必须加载原始关系,然后更新关系。使用独立关联(模型中没有 FK 属性),您只能通过使用更改跟踪来更新关系(除了在 ObjectContext 更改跟踪器中对关系条目进行更高级的修改):

    var originalPerson = this.Contacts.Include(c => c.Plan)
        .Single(c => c.Id == person.Id);
    this.Plans.Attach(person.Plan);
    
    this.Entry(originalPerson).CurrentValues.SetValues(person);
    originalPerson.Plan = person.Plan;
    
    this.SaveChanges();
    

    【讨论】:

    • 不幸的是,OP 将不得不为每个不同的实体类型创建一个单独的 Update 方法。他们发布的示例方法只是使用了一个对象。
    • @luksan:是的,我知道,但我不能使用这种方法。他必须为每个实体类型编写一个单独的 Update 方法(至少在涉及相关实体时),甚至每个实体可能有多个 Update 方法,具体取决于 Update 的类型。你知道如何执行这样一个超级通用的更新,它只需要一个object 和四行代码,就可以处理每个实体、相关实体、集合和嵌套内容等所有可能的关系更改?
    • 不,我不知道。实体框架应该自动处理它......但它没有。
    • 我没有问题...我知道 EF 不应该以这种方式使用它,但架构是很久以前定义的...我使用了这段代码:: ::::::::::::::::::::::::::::::::: PersistentMgr.Contacts.Attach(Obj);::::::::::::::::: PersistentMgr.Entry(Obj).State = EntityState.Modified;:::::::::: PersistentMgr.Entry(Obj.Plan).State = EntityState.Modified;::::::::: PersistentMgr.SaveChanges();它也没有工作
    • @Alvaro:见我上面的编辑。我制作了一个测试模型和程序来表明它“正常”有效。在您的情况下,您的模型或代码中一定有一些重要的差异会导致更新失败。但是哪一个?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多