Entity Framework Core:扩展实体而无需使用 partial

5

我需要扩展当前数据库实体(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; }
}

基于我有限的 .net 知识,我的尝试是创建一个继承自 Foo 的类 Bar,并期望通过实现扩展类 Bar 来足够实现 IFooContext

如下所示,但最终会出现错误,因为 C# 不允许使用扩展类替换父类。

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

class FooLoader: DbContext, IFooContext 
{
     DbSet<Bar> Foo; //error because DbSet<Foo> required
}

我可以做的是,在 FooLoader 中创建属性 DbSet<Bar> Bar { get; set; }, 但这样会导致两个几乎相同的数据库表:Foo 和 Bar。
因此,我进行了修改,并创建了一个包含 FooId 的类Bar, 从而得到了两个表,其中Bar表引用了Foo
class Bar 
{
     int Id { get; set; }

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

     string Description { get; set; }
}

这两种情况都会创建一个新的表,但我不确定是否符合我的要求。还有其他方法可以实现,并将新字段包含在基类/表中吗?


当您无法访问dll时,为什么要扩展它呢?您可以在上下文中完全创建Bar模型(包括Foo的属性),对吧? - sam
因为它是框架内部的一部分,依赖于IFooLoader的实现,我需要提供它的实现。但同时,我需要新的参数来满足我的使用情况。 - Tomas Ivan
1个回答

5

Code First方式至少提供了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);
}

或者

modelBuilder.Entity<Foo>()
        .HasDiscriminator<int>("FooType")
        .HasValue<Foo>(1)
        .HasValue<Bar>(2)
        .HasValue<Other>(3);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接