没有 setter 的 Entity Framework Core 属性

DiP*_*Pix 7 .net c# entity-framework-core .net-core entity-framework-core-3.1

在我的 .net core 3.1 应用程序中,我想将属性封装在某个实体中:

public class Sample : AuditableEntity
{
    public Sample(string name)
    {
        Name = name;
    }

    public int Id { get; }

    public string Name { get; }
}
Run Code Online (Sandbox Code Playgroud)

因此,我删除了所有公共设置器,因此当我想检查此类 Sample 是否已存在时,我的代码中的某个位置

_context.Samples.Any(r => r.Name == name)
Run Code Online (Sandbox Code Playgroud)

该行导致错误:System.InvalidOperationException: 'No suitable constructor found for entity type 'Sample'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'name' in 'Sample(string name)'.'

所以我添加了代码空构造函数

public class Sample : AuditableEntity
{
    public Sample() { } // Added empty constructor here

    public Sample(string name)
    {
        Name = name;
    }

    public int Id { get; }

    public string Name { get; }
}
Run Code Online (Sandbox Code Playgroud)

现在该行会导致错误:System.InvalidOperationException: 'The LINQ expression 'DbSet<Sample> .Any(s => s.Name == __name_0)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'

但是,如果我将私有集添加到Name(或公共),那么一切都会正常工作(即使没有空构造函数)。

public class Sample : AuditableEntity
{
    public Sample(string name)
    {
        Name = name;
    }

    public int Id { get; }

    public string Name { get; private set; } // added setter, removed empty constructor
}
Run Code Online (Sandbox Code Playgroud)

谁能解释一下为什么需要这个设置器,例如 Id 不需要那个设置器。

pan*_*ohn 9

这与 Farhad Jabiyev 评论中提到的反射有关。EF 无法找到该属性,它已被隐藏。当您创建它时private set,EF 可以通过反射访问它,因此一切正常。

这可以通过支持字段来完成https://learn.microsoft.com/en-us/ef/core/modeling/backing-field

来自上面的链接:支持字段允许 EF 读取和/或写入字段而不是属性。当类中的封装用于限制应用程序代码对数据的访问的使用和/或增强语义时,这可能很有用,但应该在不使用这些限制的情况下从数据库读取值和/或将值写入数据库/增强。

这意味着您必须通过像这样的 Fluent API 添加映射到您的支持字段。

modelBuilder.Entity<Sample >()
            .Property(b => b.Name)
            .HasField("_name"); // this would have to be the name of the backing field
Run Code Online (Sandbox Code Playgroud)

要访问自动道具的支持字段,您可以使用此->是否可以访问自动实现的属性后面的支持字段?

我自己添加它,这样会更容易。所以我的课看起来就像这样。您将需要上面的映射,该映射解决了我的财产是私有的问题。如果没有映射,这将失败。

public class Sample : AuditableEntity
{
    private string _name; //now EF has access to this property with the Mapping added
    public Sample(string name)
    {
        _name = name;
    }

    public int Id { get; } 

    public string Name => _name;
}
Run Code Online (Sandbox Code Playgroud)

请看看Lerman的做法-> https://www.youtube.com/watch?v=Z62cbp61Bb8&feature=youtu.be&t=1191