代码优先,EF 4.1:将下列类映射到数据库的最佳方法是什么?
本文关键字:数据库 映射 最佳 是什么 方法 EF 代码 | 更新日期: 2023-09-27 17:50:19
亲爱的专业开发者社区!
我想弄清楚如何使用代码优先正确地制作映射。
假设有几个类。一个容器类,一个基类和几个后代类。
基类:
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并运行我的代码之后,我得到两个具有以下结构的表:
容器表 IdBase table IdFirstProperty
Container_Id1
SecondProperty
Container_Id2
ThirdProperty
Container_Id3
所以我得到一个名为Base的表,它包含相同的三个字段,它们具有相同的外键作用。
现在的问题是:
我不喜欢那种冗余。专业人士如何评价这种情况,这正常吗?
我可以改变这个吗?我能得到一个更清晰的数据库结构吗?
映射这些类的最佳方法是什么?
我已经发布了一个类似的问题,但我仍然关心这个问题。
感谢您的回答和关注。
默认情况下,数据库中的表结构是正常的,并且是每层次表(TPH)映射的结果。将类层次结构映射到关系数据库表是默认策略。在此策略中,所有派生类的属性被合并到一个表中,并且类型仅通过表中的标识符列来区分。
如果你想在层次结构中每个类都有一个单独的表,你可以使用 table - per - type (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
类的表,该表仅包含该类的属性(在您的示例中仅包含Id
)和单独的表FirstDescendants
等,这些表具有派生类的属性。这两个表由一个外键关系链接,EF设法从两个表中加载所需的列,以实现您正在查询的类型的对象。
您可以在这里找到EF如何映射类层次结构的几种策略的介绍:
EF代码优先继承
编辑
在我看来,TPT是将派生类映射到关系表的更简洁的方法。TPH要求您在数据库中具有可空列,仅用于您可能希望在模型中具有所需属性的映射。但另一方面,TPH可能性能更高,因为查询不需要连接不同的表。
一个可能的经验法则是:
如果大多数属性都在基类中,而派生类只添加了一些额外的属性,则可以使用TPH
如果基类不包含属性或只有少数属性,并且大多数属性都在派生类中,则使用TPT。
但是这两种方法的优缺点——也是第三种每具体类表(TPC)——要好得多,在上面的链接系列文章中有详细的解释。