EF 核心 3.1.1 - 拥有的实体代理问题

EF core 3.1.1 - owned entity proxy problem

我最近遇到了 EF core 3.1.1 中的奇怪问题。我们正在尝试从 EF6 迁移到 EF 核心,并且拥有实体的行为与 EF6 中的复杂类型不同。当拥有的实体由空对象初始化时,EF 无法检测到更改。这个问题只针对 MSSQL 发生,针对 "In memory" 数据库一切似乎都很好。

public class OwnedEntityProxyTests
{
    [Fact]
    public void InMemoryTest()
    {
        Assert.True(Test(new DbContextOptionsBuilder<TestContext>()
            .UseInMemoryDatabase(databaseName: "Test")));
    }

    [Fact]
    public void MsSqlTest()
    {
        Assert.True(Test(new DbContextOptionsBuilder<TestContext>()
            .UseSqlServer("Data Source=.;MultipleActiveResultSets=True;Integrated Security=True")));
    }

    private static bool Test(DbContextOptionsBuilder<TestContext> builder)
    {
        var options = builder.UseLazyLoadingProxies().Options;
        using (var ctx = new TestContext(options))
        {
            ctx.TestEntities.RemoveRange(ctx.TestEntities.ToArray());
            ctx.TestEntities.Add(new TestEntity());
            ctx.SaveChanges();
        }

        using (var ctx = new TestContext(options))
        {
            var e = ctx.TestEntities.Single();
            e.TestOwnedEntity.Code = "test";
            return ctx.ChangeTracker.Entries().Any(o => o.State != EntityState.Unchanged);
        }
    }
}

public class TestContext : DbContext
{
    public TestContext() : base(new DbContextOptionsBuilder<TestContext>()
        .UseSqlServer("Data Source=.;MultipleActiveResultSets=True;Integrated Security=True")
        .UseLazyLoadingProxies()
        .Options)
    {
    }

    public TestContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<TestEntity> TestEntities { get; set; }
}

public class TestEntity
{
    public long Id { get; set; }
    public virtual TestOwnedEntity TestOwnedEntity { get; private set; } = new TestOwnedEntity();
}

[Owned]
public class TestOwnedEntity
{
    public string Code { get; set; }
}

在此示例中,上下文应检测变化。 "In memory database" 正确检测到它,但 MS Sql 提供程序未能检测到它。这很可能是由于拥有类型周围缺少代理造成的。当拥有类型的所有属性都是默认的并且没有初始化拥有的实体为空时代理丢失。

你能给我一些正确设置的提示吗?我不想删除拥有实体的默认初始化,它会迫使我们检查所有实体是否为 null。

整个项目在github

我相信您必须为 TestOwnedEntity 实现方法 Equals,例如:

public override bool Equals(object obj)
{
    var other = obj as TestOwnedEntity;
    if (other == null) return false;
    if (object.ReferenceEquals(this, obj) return true;
    return other.Code == this.Code;
}

最后他们在 EF 核心论坛上提供了帮助 https://github.com/dotnet/efcore/issues/20213

public class TestEntity
{
    public long Id { get; set; }

    private TestOwnedEntity _testOwnedEntity;
    public virtual TestOwnedEntity TestOwnedEntity
    {
        get
        {
            if (_testOwnedEntity == null)
            {
                _testOwnedEntity = new TestOwnedEntity();
            }
            return _testOwnedEntity;
        }
        private set { _testOwnedEntity = value; }
    }
}

您可以在此处找到我测试中的更改:https://github.com/PospisilBohumir/EfCoreTests/tree/FinalFix