亲爱的专业开发人员社区!
我试图弄清楚如何首先使用代码正确制作映射。
假设有几个类。一个容器类、一个基类和几个后代类。
基类:
public class Base {
public int Id { get; set; }
}
后代类:
public class FirstDescendant {
public string FirstProperty { get; set; }
}
public class SecondDescendant {
public int SecondProperty { get; set; }
}
public class ThirdDescendant {
public int ThirdProperty { get; set; }
}
容器类:
public class Container {
public int Id { get; set; }
public ICollection<FirstDescendant> FirstDescendants { get; set; }
public ICollection<SecondDescendant> SecondDescendants { get; set; }
public ICollection<ThirdDescendant> ThirdDescendants { get; set; }
}
默认情况下,创建 DbContext 并运行代码后,我会得到两个具有以下结构的表:
The Container table
Id
The Base table
Id
FirstProperty
Container_Id1
SecondProperty
Container_Id2
ThirdProperty
Container_Id3
因此我得到一个名为 Base 的表,其中包含相同的三个字段,这些字段具有相同的外键作用。
现在问题:
我不喜欢这种冗余。专业界如何评价这种情况,这正常吗?
我可以更改此设置吗?我可以获得更清晰的数据库结构吗?
映射此类的最佳方法是什么?
我已经发布了a similar question但我还是很关心这个问题。
感谢您的回答和关注。
最佳答案
您默认获得的数据库中的表结构是正常的,是Table-Per-Hierarchy (TPH)映射的结果。将类层次结构映射到关系数据库表是默认策略。在此策略中,所有派生类的属性都合并到一个表中,并且仅通过表中的鉴别器列来区分类型。
如果您希望层次结构中的每个类都有一个单独的表,您可以使用每个类型表 (TPT) 策略。但这不是默认设置,您必须通过数据注释明确指定...
[Table("FirstDescendants")]
public class FirstDescendant : Base
{
public string FirstProperty { get; set; }
}
// the same with the other derived classes
...或 Fluent 代码:
modelBuilder.Entity<FirstDescendant>().ToTable("FirstDescendants");
// the same with the other derived classes
这样您就可以获得一张适合您的Base
的 table 。类,仅包含此类的属性(在您的示例中仅包含 Id
)和单独的表 FirstDescendants
等等,它们具有派生类的属性。这些表通过外键关系链接,EF 设法从两个表中加载所需的列,以具体化您正在查询的类型的对象。
您可以在此处找到 EF 如何映射类层次结构的几种策略的介绍:
Inheritance with EF Code First
编辑
在我看来,TPT 是将派生类映射到关系表的更清晰的方法。 TPH 要求您在数据库中拥有可为空的列,仅用于您可能希望拥有模型中所需属性的映射。但另一方面,TPH 的性能可能会更高,因为查询不需要连接不同的表。
可能的决定经验法则可能是:
如果大多数属性位于基类中,而派生类仅添加一些附加属性,则可以使用 TPH。
如果基类不包含或仅包含少数属性,并且大多数属性都在派生类中,则使用 TPT。
但是这些方法的优点和缺点 - 也是第三种Table-Per-Concrete-Class (TPC) - 更好,并且在上面的链接文章系列中有详细解释。
关于c# - 代码首先,EF 4.1 : What is the best way to map the following classes with a database. ..?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5694257/