首页 > 解决方案 > 存在列表导航属性时 AutoDetectChanges 不起作用

问题描述

我遇到了一个错误,在某些依赖 EF6 的代码中,没有检测到更改(尽管它们被持久化到数据存储区)。

使用List<Child>导航属性时,如果父对象中的属性发生更改,则不会检测到更改。EntityState 保持不变。

示例控制台应用程序(带有 NuGet EntityFramework 6.2 的 .NET Framework 4.7.2)代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.ComponentModel.DataAnnotations.Schema;

namespace EFStateTest
{
    public class Tests
    {
        public static void Main()
        {
            var context = new StandaloneContext();


            /* First time run, generate some test data to work with */
            if (!context.Set<ParentTable>().Any())
            {
                ParentTable p = new ParentTable()
                {
                    Data = "Foo",
                    Children = new List<ChildTable>()
                    {
                        new ChildTable()
                        {
                            ManyData = "Bar",
                        },
                    },
                };

                context.Set<ParentTable>().Add(p);
            }
            /* nth run, do the test */
            else
            {
                var p = context.Set<ParentTable>().FirstOrDefault();        // Get our test record

                p.Data = DateTime.Now.Ticks.ToString();     // Change some data

                try
                {
                    // Get the state
                    object d = p.GetType().GetField("_entityWrapper").GetValue(p);
                    System.Data.Entity.Core.Objects.ObjectStateEntry ose = d.GetType().GetProperty("ObjectStateEntry").GetValue(d) as System.Data.Entity.Core.Objects.ObjectStateEntry;
                    Console.WriteLine(ose.State);
                }
                catch
                {
                    Console.WriteLine("Not a proxy class");
                }
            }

            context.SaveChanges();
            Console.WriteLine("DONE");
            Console.ReadLine();
        }
    }

    // Context
    public class StandaloneContext : DbContext
    {
        public StandaloneContext() : base("Server=(local);Database=EFTest;Integrated Security=SSPI")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new ParentTableSchema());
            modelBuilder.Configurations.Add(new ChildTableSchema());

            base.OnModelCreating(modelBuilder);
        }
    }

    public class ParentTable
    {
        public virtual int Id { get; set; }
        public virtual string Data { get; set; }

        public virtual List<ChildTable> Children { get; set; }
    }

    public class ChildTable
    {
        public virtual int Id { get; set; }
        public virtual int ParentId { get; set; }
        public virtual string ManyData { get; set; }

        public virtual ParentTable Parent { get; set; }
    }

    public class ParentTableSchema : EntityTypeConfiguration<ParentTable>
    {
        public ParentTableSchema()
        {
            HasKey(m => m.Id)
                .Property(m => m.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            HasMany(m => m.Children)
                .WithRequired(c => c.Parent)
                .HasForeignKey(c => c.ParentId);
        }
    }

    public class ChildTableSchema : EntityTypeConfiguration<ChildTable>
    {
        public ChildTableSchema()
        {
            HasKey(m => m.Id)
                .Property(m => m.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }
}

运行一次以在本地计算机上生成数据库,并再次显示错误。改变父对象的属性p.Data = DateTime.Now.Ticks.ToString();

现在,如果您删除 的导航集合List<ChildTable> Children,那么问题就会消失(但我有点想要导航属性)并且更改跟踪器正确更改为已修改。

我已经有一个修复,但它没有回答为什么。将导航属性更改为定义为ICollection<ChildTable>而不是 List、IList 等,它也可以工作。

到目前为止,我在 EF 上阅读的文档说导航属性需要实现 ICollection - List 就是这样做的。那么这里给出了什么?我是不是搞错了什么,或者完全错过了什么?

标签: c#entity-framework-6navigation-properties

解决方案


推荐阅读