简体   繁体   English

由于后备字段,EF核心代码首先引发错误的问题

[英]Problem with EF-Core Code first throwing error because of backing field

I'm having trouble getting my backing fields to work, i've tried my way through using this documentation: https://docs.microsoft.com/en-us/ef/core/modeling/backing-field with no luck. 我无法让我的后备字段正常工作,我尝试使用以下文档尝试了方法: https : //docs.microsoft.com/en-us/ef/core/modeling/backing-field ,没有运气。

When i try to add the migration i'm greeted with this error: 当我尝试添加迁移时,遇到此错误:

The property 'Workflow._step1' is of type 'Step1' which is not supported by current database provider. 属性“ Workflow._step1”的类型为“ Step1”,当前数据库提供程序不支持该属性。 Either change the property CLR type or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'. 更改属性CLR类型或使用'[NotMapped]'属性或'OnModelCreating'中的'EntityTypeBuilder.Ignore'忽略属性。

Multiple workflows can use the same step, so i want it to be saved like this 多个工作流程可以使用同一步骤,所以我希望这样保存它

Workflow 
{
    Id,
    Step1Id
    Step2Id
}

Example that does not work code: 无法使用代码的示例:

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");
    }
}

Here is the case. 就是这种情况。 By EF Core terminology these are not properties, but navigation properties, so they cannot be configured with Property fluent API (and in general are not returned by any metadata/entry method having Property / Properties in the name). 根据EF Core的术语,这些不是属性,而是导航属性,因此无法使用Property fluent API进行配置(通常,名称中包含Property / Properties的任何元数据/条目方法都不会返回它们)。

Instead, they are configured through relationship related fluent APIs. 相反,它们是通过与关系相关的流畅API进行配置的。 The problem with mapping the backing field though is that there is no natural fluent API for that similar to "properties", so you have to use directly the metadata. 但是,映射后备字段的问题是没有类似于“属性”的自然流利的API,因此您必须直接使用元数据。

The configuration could be like this: 配置可能是这样的:

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

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

or taking into account that the backing field names follow one of the EF Core naming conventions: 或考虑到支持字段名称遵循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);

But this is also the EF Core default behavior. 但这也是EF Core的默认行为。 So the actual problem is not the backing field, but the fact that EF Core by default does not include read only (no setter) properties (simple or navigation, doesn't matter). 因此,实际问题不在于支持领域,而是默认情况下EF Core不包括只读 (无设置器)属性(简单或导航都无所谓)的事实。 Hence the minimal configuration to make this work is like this: 因此,使这项工作最少的配置是这样的:

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

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

Update: In order to force EF Core to use the backing field for both set (when reading from database) and get (change tracking, storing to database), use the second configuration - with .Metadata.DependentToPrincipal.SetPropertyAccessMode(PropertyAccessMode.Field) . 更新:为了强制EF Core同时使用set (从数据库中读取)和get (更改跟踪,存储到数据库)的后备字段,请使用第二种配置-带有.Metadata.DependentToPrincipal.SetPropertyAccessMode(PropertyAccessMode.Field)

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

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