【问题标题】:EF Core: No backing field could be found for property of entity type and the property does not have a getterEF Core:找不到实体类型属性的支持字段,并且该属性没有 getter
【发布时间】:2020-08-14 17:37:20
【问题描述】:

我在 EF Core 中遇到以下错误:找不到实体类型“Child”的属性“ParentId”的支持字段,并且该属性没有 getter。

这是我对子实体的配置:

            // create shadow property for Parent
            builder.Property<int>("ParentId").IsRequired();

            // make shadow property and foreign key the PK as well
            // i know this may not make the most sense here 
            // in this scenario but it's what I want to do.
            builder.HasKey("ParentId");

            // configure FK
            builder.HasOne(o => o.Parent)
                .WithOne()
                .HasForeignKey<Child>("ParentId");

还有我的实体:

public class Parent
{
    public int Id { get; set; }
}

public class Child 
{
    public Parent Parent { get; private set; }

    public void SetParent(Parent p) => Parent = p;
}

当我调用dbContext.Children.Contains(myChild)时出现错误:

var child = new Child();
child.Parent = new Parent();

dbContext.Children.Add(child);
dbContext.SaveChanges();

// works fine
Assert.True(dbContext.Children.Any());

// throws InvalidOperationException
Assert.True(dbContext.Children.Contains(myChild)):

如果我将阴影属性作为真实属性添加到模型中:

public class Child 
{
    public int ParentId { get; set;} 

    public Parent Parent { get; private set; }

    public void SetParent(Parent p) => Parent = p;
}

然后一切正常。但如果可能的话,我想保留它的影子属性。

【问题讨论】:

    标签: c# entity-framework entity-framework-core


    【解决方案1】:

    更新:

    刚查看了3天前发布的EF Core 3.1.7,异常消失了,说明已经报告/识别并修复。因此,您可以简单地升级到该版本。

    原文:

    shadow 属性的配置没问题。不幸的是,您遇到了 EF Core 3.x 错误之一。

    为了将Contains 方法转换为 SQL,EF Core 必须将其转换为 PK 相等比较,类似于(在伪代码中)

    dbContext.Children.Any(c => PK(c) == PK(myChild))
    

    从异常堆栈跟踪中可以看出,当 PK 是影子属性时显然没有这样做。

    我目前检查了最新的 EF 5 预览版,它似乎已修复(问题消失了)。因此,在它发布之前,解决方法是用相应的显式 PK 比较替换隐式实体相等比较(例如 Contains(entity)Equals(entity)== entity 等)。

    在这种情况下,而不是

    dbContext.Children.Contains(child)
    

    你可以使用任何一个

    dbContext.Children.Any(c => c.Parent.Id == child.Parent.Id)
    

    (由于另一个 v3.x 缺陷导致 SQL 翻译变差)

    dbContext.Children.Any(c => EF.Property<int>(c, "ParentId") == child.Parent.Id)
    

    (与 v5.0 一样的正确 SQL 翻译,但使用“魔术”字符串并需要显式指定影子属性名称和类型)

    【讨论】:

    • 我深深佩服你一次又一次进入这个雷区的勇气。
    • 谢谢,我很高兴知道这是一个错误,而不是我做错了什么!
    • 对于其他跌跌撞撞来到这里的人,这篇文章也有帮助:stackoverflow.com/questions/61691178/…
    【解决方案2】:
    public class Child 
    {
        public int ParentId{get;set;}
        public Parent Parent { get; private set; }
    
        public void SetParent(Parent p) => Parent = p;
    }
    

    你应该定义你的外键变量并记住私有集不会在 db 中创建关系

    【讨论】:

    • 抱歉,您能再解释一下吗?我看到你添加了我问题的最后一部分作为答案,但正如我所说,这是我试图避免的。我的配置指定了外键(参见问题的第一个 sn-p)
    • 我希望使用导航属性,根据 MS 文档,这是可能的。
    猜你喜欢
    • 1970-01-01
    • 2021-12-13
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 2021-11-06
    • 1970-01-01
    相关资源
    最近更新 更多