C# EF核心基本实体类继承和只读属性

C# EF核心基本实体类继承和只读属性,c#,entity-framework,asp.net-core,entity-framework-core,.net-core,C#,Entity Framework,Asp.net Core,Entity Framework Core,.net Core,是否可以这样做: public abstract class BaseEntity : IEntity { private Guid _id; private DateTime _createdOn; private DateTime _modifiedOn; private byte[] _timestamp; [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public G

是否可以这样做:

public abstract class BaseEntity : IEntity
{
    private Guid _id;
    private DateTime _createdOn;
    private DateTime _modifiedOn;
    private byte[] _timestamp;

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id => _id;

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime CreatedOn => _createdOn;

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime ModifiedOn => _modifiedOn;

    [Timestamp]
    public byte[] Timestamp => _timestamp;
}
这是基类,所有实体都应从该类继承。而且这个属性应该是只读的(我正在使用),因为EF需要处理它们

public class Category : BaseEntity
{
    [Required]
    public string Name { get; set; }

    public string Description { get; set; }
}
而OnModelCreating的
为空。
当我运行迁移时,会收到以下消息:

“实体类型”Project.Database.Models.Category“需要主 要定义的键


问题是BaseEntity.Id属性是只读的

您的Id属性被实现为(语法=>syntax),这只是get-only属性的语法糖

因此,您的代码:

public Guid Id => _id;
相当于:

public Guid Id { get { return _id; } }

EF必须能够设置映射属性的值。您必须使用传统语法来实现该属性,并且必须提供setter。如果上下文与模型位于同一程序集中,则可以将setter标记为internal,以便该属性在程序集中外部只读。如果您的上下文位于不同的程序集中,您仍然可以将setter标记为internal,然后使用该属性使包含您的上下文的程序集可以看到内部内容。

问题在于BaseEntity.Id属性是只读的

您的Id属性被实现为(语法=>syntax),这只是get-only属性的语法糖

因此,您的代码:

public Guid Id => _id;
相当于:

public Guid Id { get { return _id; } }

EF必须能够设置映射属性的值。您必须使用传统语法来实现该属性,并且必须提供setter。如果上下文与模型位于同一程序集中,则可以将setter标记为internal,以便该属性在程序集中外部只读。如果您的上下文位于不同的程序集中,您仍然可以将setter标记为internal,然后使用该属性使包含您的上下文的程序集中的内部可见。

这似乎是一个错误,因为如果您提供
public
internal
protected
(但不提供
private
或none),则该功能有效
Id
属性的setter,或者如果通过Fluent API显式指定派生的实体的键

modelBuilder.Entity<Category>().HasKey(e => e.Id);
modelBuilder.Entity().HasKey(e=>e.Id);
这当然违背了使用基类属性的全部目的


您可以考虑将其报告给EF核心。

< P>这似乎是一个bug,因为如果您提供<代码>公共<代码>、<代码>内部<代码>或<代码>受保护< /代码>(但不是<代码>私下< /代码>或无)设置器用于<代码> ID <代码>属性,或者,如果通过Fluent API显式指定派生的实体的键

modelBuilder.Entity<Category>().HasKey(e => e.Id);
modelBuilder.Entity().HasKey(e=>e.Id);
这当然违背了使用基类属性的全部目的


<>你可以考虑把它报告给EF核心。

不应该用后退字段来处理。那么应该在哪里使用支持字段呢?支持字段是_id,这在两种方法实现中都使用。不过,backing字段不是映射到数据库列的字段。财产是。backing字段只是模型类中的一个私有机制,实体框架(以及其他所有内容)不知道/不关心它。backing字段是在创建对象时设置的,属性是EF映射到数据库的内容。我还是不明白为什么这样不行。“配置备份字段时,EF将在从数据库具体化实体实例时直接写入该字段(而不是使用属性设置器)。如果没有属性设置器,或者设置器包含在为从数据库加载的现有实体设置初始属性值时不应执行的逻辑,则此选项非常有用。“-来自ef core Docs,但您的语法与将按约定查找的备份字段的示例不匹配。您是否尝试过不使用表达式体语法?您是否尝试过在上下文的OnModelCreating覆盖中使用Fluent API.HasAnnotation(“BackingField”,“_id”)方法?这不应该用backing字段处理吗。那么应该在哪里使用支持字段呢?支持字段是_id,这在两种方法实现中都使用。不过,backing字段不是映射到数据库列的字段。财产是。backing字段只是模型类中的一个私有机制,实体框架(以及其他所有内容)不知道/不关心它。backing字段是在创建对象时设置的,属性是EF映射到数据库的内容。我还是不明白为什么这样不行。“配置备份字段时,EF将在从数据库具体化实体实例时直接写入该字段(而不是使用属性设置器)。如果没有属性设置器,或者设置器包含在为从数据库加载的现有实体设置初始属性值时不应执行的逻辑,则此选项非常有用。“-来自ef core Docs,但您的语法与将按约定查找的备份字段的示例不匹配。您是否尝试过不使用表达式体语法?您是否尝试过在上下文的OnModelCreating覆盖中使用Fluent API.HasAnnotation(“BackingField”,“_id”)方法?我不认为这是一个bug。正如您所指出的,如果属性没有setter,它就不起作用(也不能起作用)。在OP的代码中,属性没有setter。它不应该起作用,我不明白这是怎么回事。正如您所指出的,如果属性没有setter,它就不起作用(也不能起作用)。在OP的代码中,属性没有setter。它不应该起作用。