繁体   English   中英

找不到实体类型的属性的支持字段,并且该属性没有 getter

[英]No backing field could be found for property of entity type and the property does not have a getter

我遇到了一个例外

System.InvalidOperationException: No backing field could be found for property 'ApartmentId' of entity type 'Address' and the property does not have a getter.

这是我的Apartment class:

public class Apartment
{
    public Apartment(Address address)
    {
        Address = address;
    }

    private Apartment()
    {
    }

    public int Id { get; private set; }
    public Address Address { get; private set; }
}

这是我的Address值 object class:

public class Address : IEquatable<Address>
{
    private Address()
    {
    }

    public Address(string streetNumber, string streetName, string city, string state, string zipCode)
    {
        StreetNumber = streetNumber;
        StreetName = streetName;
        City = city;
        State = state;
        ZipCode = zipCode;
    }

    public string StreetNumber { get; private set; }
    public string StreetName { get; private set; }
    public string City { get; private set; }
    public string State { get; private set; }
    public string ZipCode { get; private set; }

    public bool Equals(Address other)
    {
        if (ReferenceEquals(null, other))
        {
            return false;
        }

        if (ReferenceEquals(this, other))
        {
            return true;
        }

        return String.Equals(StreetNumber, other.StreetNumber, StringComparison.OrdinalIgnoreCase) &&
               String.Equals(StreetName, other.StreetName, StringComparison.OrdinalIgnoreCase) &&
               String.Equals(City, other.City, StringComparison.OrdinalIgnoreCase) &&
               String.Equals(State, other.State, StringComparison.OrdinalIgnoreCase) &&
               String.Equals(ZipCode, other.ZipCode, StringComparison.OrdinalIgnoreCase);
    }
}

在我的实体配置中,我使用builder.OwnsOne(a => a.Address); . 在我的存储库中,我进行了以下调用:

    public async Task<Apartment> GetByAddressAsync(Address address)
    {
        return await _context.Apartments.FirstOrDefaultAsync(a => a.Address.Equals(address));
    }

它会产生上述异常。 有任何想法吗? 我不知道为什么它说我的Address值 object 中有一个“ApartmentId”。

异常消息当然是可笑的,与实际问题没有共同之处,即表达式

a => a.Address.Equals(address)

它是IQueryable表达式树的一部分,因此 EF Core 正在尝试将其转换为 SQL。

像封装这样的面向对象特性不能很好地与基于可见性和知识的表达式翻译配合使用。 EF Core 不是反编译器,它看不到Equals方法的实现。 他们通常对未知方法所做的是抛出运行时异常,要求您使用可翻译构造或显式切换到客户端评估。

但是实体类型有特殊处理。 EF Core 试图通过将其隐式转换为 PK(主键)比较来支持相等比较( == 、'!= , Equals`)翻译。

这就是您拥有的实体类型的问题。 请注意,拥有的实体类型仍然是实体类型,但像您的Address这样的引用拥有的类型没有自己的 PK,因此例外。

当然,他们所做的是一个错误,但即使他们“修复”它,修复也只是不同的运行时异常。

解决方案当然是不使用Equals方法,而是显式的成员比较,例如

a => a.Address.StreetNumber.ToUpper() == address.StreetNumber.ToUpper()
    && a.Address.StreetName.ToUpper() == address.StreetName.ToUpper()
    && a.Address.City.ToUpper() == address.City.ToUpper()
    && a.Address.State.ToUpper() == address.State.ToUpper()
    && a.Address.ZipCode.ToUpper() == address.ZipCode.ToUpper()

请注意,字符串比较由数据库控制,因此如果您需要强制执行不区分大小写的比较,则需要显式ToUpper()

现在我知道这是代码重复并破坏了封装,但这是获得服务器端过滤的唯一方法(除非您使用诸如NeinLinq.EntityFrameworkCoreDelegateDecompiler等的Lambda 注入之类的第 3 方库)。

因为读取整个表格后的客户端过滤就像

_context.Apartments.AsEnumerable().FirstOrDefault(a => a.Address.Equals(address))

将是性能杀手(并且是在 EF Core 3.0+ 中删除隐式客户端评估的原因),而不是缺少自然async支持(需要额外的 package,这反过来会导致 EF Core DbSet出现问题 - 请参阅转换 EF从 2.2 到 3.0 的核心查询 - 异步等待)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM