由于支持字段,EF-Core 代码首先抛出错误的问题

Tan*_*ooe 5 c# entity-framework-core

我在让我的支持字段工作时遇到问题,我已经尝试过使用此文档:https : //docs.microsoft.com/en-us/ef/core/modeling/backing-field没有运气。

当我尝试添加迁移时,遇到此错误:

属性“Workflow._step1”属于“Step1”类型,当前数据库提供程序不支持该属性。使用“[NotMapped]”特性或使用“OnModelCreating”中的“EntityTypeBuilder.Ignore”更改属性 CLR 类型或忽略该属性。

多个工作流可以使用相同的步骤,所以我希望它像这样保存

Workflow 
{
    Id,
    Step1Id
    Step2Id
}
Run Code Online (Sandbox Code Playgroud)

不起作用的代码示例:

public class Workflow 
{
    private Step1 _step1;
    private Step2 _step2;

    public Guid Id { get; set; } = Guid.NewGuid();

    public bool Step1Enabled => true;
    public Step1 Step1 => Step1Enabled ? _step1 : null;

    public bool Step2Enabled => _step1.Completed;
    public Step2 Step2 => _step2Enabled ? _step2 : null;
}

public class Step1 
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public bool StatusUniqueToStep1 { get; set; }
    public bool Completed {get; set; }
}

public class Step2 
{
    public Guid Id { get; private set; } = Guid.NewGuid();
    public bool StatusUniqueToStep2 { get; set; }
    public bool Completed {get; set; }
}

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) :base(options)
    {}

    public DbSet<Workflow> Workflows { get; set; }
    // Tried adding these, does not work.
    // public DbSet<Step1> Step1 { get; set; }
    // public DbSet<Step2> Step2 { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Tried adding these, does not work.
        // modelBuilder.Entity<Step1>();
        // modelBuilder.Entity<Step2>();

        modelBuilder.Entity<Workflow>()
            .Property<Step1>("_step1");

        modelBuilder.Entity<Workflow>()
            .Property<Step2>("_step2");
    }
}
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 9

这是这种情况。通过EF核心术语这些都不是属性,但导航属性,因此它们不能与被配置Property流利API(和一般不具有任何元数据/输入方法返回Property/Properties中的名称)。

相反,它们是通过关系相关的流畅 API 进行配置的。映射后备字段的问题在于,没有类似于“属性”的自然流畅的 API,因此您必须直接使用元数据。

配置可能是这样的:

modelBuilder.Entity<Workflow>()
    .HasOne(e => e.Step1)
    .WithMany()
    .Metadata.DependentToPrincipal.SetField("_step1");

modelBuilder.Entity<Workflow>()
    .HasOne(e => e.Step2)
    .WithMany()
    .Metadata.DependentToPrincipal.SetField("_step2");
Run Code Online (Sandbox Code Playgroud)

或考虑到支持字段名称遵循 EF Core 命名约定之一:

modelBuilder.Entity<Workflow>()
    .HasOne(e => e.Step1)
    .WithMany()
    .Metadata.DependentToPrincipal.SetPropertyAccessMode(PropertyAccessMode.Field);

modelBuilder.Entity<Workflow>()
    .HasOne(e => e.Step2)
    .WithMany()
    .Metadata.DependentToPrincipal.SetPropertyAccessMode(PropertyAccessMode.Field);
Run Code Online (Sandbox Code Playgroud)

但这也是 EF Core 的默认行为。因此,实际问题不在于支持字段,而在于 EF Core 默认情况下不包含只读(无 setter)属性(简单或导航无关紧要)。因此,使这项工作的最低配置是这样的:

modelBuilder.Entity<Workflow>()
    .HasOne(e => e.Step1);

modelBuilder.Entity<Workflow>()
    .HasOne(e => e.Step2);
Run Code Online (Sandbox Code Playgroud)

更新:为了强制 EF Core 对set(从数据库读取时)和get(更改跟踪、存储到数据库)使用支持字段,请使用第二个配置 - 与.Metadata.DependentToPrincipal.SetPropertyAccessMode(PropertyAccessMode.Field).