Entity Framework Core:扩展实体而无需部分

Tom*_*van 5 .net c# entity-framework entity-framework-core .net-core

我必须扩展当前的数据库实体 ( Foo) 以包含新字段。听起来很容易,但我很难找到解决方案。问题是,我无法为其创建分部类,Foo因为它是我正在使用的 dll 的一部分。我无法Foo按照我的意愿请求修改(或由我自己完成)。

我的项目结构与此类似:

// unmodifiable because part of dll
class Foo 
{
    int Id { get; set; }
    string Name { get; set; }
}

// unmodifiable because part of dll
interface IFooContext 
{
     DbSet<Foo> Foo { get; set; }
}

class FooContext: DbContext, IFooContext 
{
     DbSet<Foo> Foo { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

由于我对 .net 的了解有限,我尝试创建Bar扩展的类,并期望使用扩展类Foo来实现它就足够了。IFooContextBar

您可以在下面看到,但最终会出现错误,因为 C# 不允许使用可与父级互换的扩展类。

class Bar: Foo 
{
     string Description { get; set; } //new field
}

class FooLoader: DbContext, IFooContext 
{
     DbSet<Bar> Foo; //error because DbSet<Foo> required
}
Run Code Online (Sandbox Code Playgroud)

我能做的是DbSet<Bar> Bar { get; set; }在内部创建属性FooLoader,但最终我会得到两个几乎相同的数据库表:Foo 和 Bar。

所以我进行了修改并创建了Bar包含FooId. 它生成两个表,其中Bar表引用了Foo.

class Bar 
{
     int Id { get; set; }

     Foo Foo { get; set; }
     int FooId { get; set; }

     string Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这两种情况都会创建一个我不确定的新表,是否是我想要的。但是有没有其他方法可以做到这一点并将新字段包含在基类/表中?

Don*_*ong 5

代码优先方法为您提供了至少 3 个选项来将您的(继承层次结构)实体映射到表:

  1. 每个层次结构表 (TPH)
  2. 每个类型的表 (TPT)
  3. 每个混凝土类型的表 (TPC)

您需要的是第一种方法,它将您的基类和层次结构映射到一个表,但将添加一个附加列(“Discriminator”作为默认名称)来标识它们Type,哪一列将用于恢复到其自己的类型当您从数据库查询整行时。最重要的是:与其他两种方法相比,第一种方法也提供了最佳性能。

这里有一些很好的帖子,您可以在其中找到实现:

  1. https://learn.microsoft.com/en-us/ef/core/modeling/relational/inheritance
  2. https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/inheritance?view=aspnetcore-3.1
  3. https://www.learnentityframeworkcore.com/inheritance/table-per-hierarchy

就是这样:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    ....

    modelBuilder.Entity<Foo>()
            .HasDiscriminator<string>("FooType")
            .HasValue<Foo>(nameof(Foo))
            .HasValue<Bar>(nameof(Bar))
            .HasValue<Other>(nameof(Other));
    ...
    base.OnModelCreating(modelBuilder);
}
Run Code Online (Sandbox Code Playgroud)

或者

modelBuilder.Entity<Foo>()
        .HasDiscriminator<int>("FooType")
        .HasValue<Foo>(1)
        .HasValue<Bar>(2)
        .HasValue<Other>(3);
Run Code Online (Sandbox Code Playgroud)