【问题标题】:Model Inheritance and DB Normalization in CoreCore 中的模型继承和数据库规范化
【发布时间】:2018-12-07 17:42:18
【问题描述】:

执行 C# ASP.NET Core 2.1 MVC 并按照 Contoso 教程进行操作,在这些教程中,您有一个 Student 模型和一个从具有公共属性的 People 模型继承的 Instructor 模型。迁移后,这会生成一个带有“鉴别器”字段的单个 People 表。

在需要 3NF 规范化时,这个带有鉴别器的单表是否可以接受,或者是否有一种方法可以在减少冗余代码的同时为数据库管理员生成规范化布局?

编辑以响应 cmets:

这就是我喜欢堆栈溢出的地方,分享想法和解释。所以这是我对 3NF 的解释,如果我错了,请分享你的解释,以便我学习。

public abstract class BaseModel
{
    public int ID { get; set; }
}

public abstract class Person : BaseModel
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

public class Student : Person
{
    public DateTime EnrollmentDate { get; set; }
}

public class Instructor : Person
{
    public DateTime HireDate { get; set; }
}

结果是一个单一的“人”表,如下所示: 身份证 |姓氏 |名字 |鉴别器 |聘用日期 |报名日期

判别器是 NVARCHAR(MAX) 或者换句话说是一个字符串,它可以是“Instructor”或“Student”

因此判别器将具有冗余值,这些值应该在它们自己的表中并使用整数外键。

还有传递依赖,因为 Student 确定 EnrollmentDate 但与 HireDate 无关,而 Instructor 则相反。所以任何一个日期列也不属于这个表,我相信这个表甚至不符合 2NF 的要求。

我相信一组正确规范化的表格应该是这样的:

-人- 身份证 |姓氏 |名字

-学生- 个人ID |报名日期

-教师- 个人ID |入职日期

-学生- 身份证 |姓氏 |名字 |报名日期

-教师- 身份证 |姓氏 |名字 |入职日期

所以回到原来的帖子和问题,一个带有鉴别器列的“主”表是否可以进行规范化,因为目标应该是为数据库管理员正确结构化的表,同时删除冗余属性程序员担心为其编写格式、验证和错误消息。关于第二点,请分享其他解决方案,例如是否可以在 DTO 或 ViewModel 中完成数据验证。

【问题讨论】:

  • 您可以使用table per type or table per hierarchy。如果你想要 3nf,你需要每种类型的表。
  • EF-Core 目前不支持 Table per Type,但有一些 alternative solutions 可能适合您。
  • 你们说得都对,Igor 说得对,我想要 TPT……但 Erik 说得对,即使在使用数据注释和手动按摩迁移之后,我似乎还是无法正确.因此,在 EF-Core 获得适当支持之前……或者我找到 Nuget,我认为我最好的选择是在 SQL Server Management Studio 中构建并拉入数据库,或者如果我先编写代码,不要使用模型继承和现在我将看看是否可以在数据传输对象或视图模型中使用继承和数据注释。
  • 请通过在帖子本身中包含足够的详细信息(作为文本)来使您的帖子独立。这包括——你为什么认为会违反 3NF? (有一个子类型/继承习语违反 2NF,因为在给定子类型表的每一行中包含相同标记值的列,但这不是问题,因为它是一个习语。)@Igor 你为什么认为 table-每个层次结构——或每个类型的表——违反 3NF? (您的链接毫无根据地暗示每个层次结构的表违反了 3NF,但事实并非如此。)

标签: c# inheritance entity-framework-core database-normalization


【解决方案1】:

修复是删除单行

型号:

public abstract class BaseModel
{
    public int ID { get; set; }
}
public abstract class BasePerson
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
}
public class Student
{
    public DateTime EnrollmentDate
}
public class Instructor
{
    public DateTime HireDate
}

数据库上下文:

public class SchoolContext : DbContext
{
    public SchoolContext(DbContextOptions<SchoolContext> options)
        : base(options)
    {
    }
    public DbSet<Student> Students { get; set; }
    public DbSet<Instructor> Instructors { get; set; }
    // public DbSet<BasePerson> People { get; set; }
}

如果您像 Contoso 教程显示的那样包含 People DbSet,当您执行迁移和更新数据库时,您会在数据库中获得一个 People 表,其中包含一个名为 Discriminator 的列,所有继承的字段的值都为学生或教师以及表格末尾的任何唯一字段。

我突然想到 BaseModel 中没有单个 Model 表,因为 DbContext 中没有 DbSet Models。所以我尝试了它并且它有效,删除了 DbSet People 的行,你得到的是具有所有继承字段的 Student 和 Instructors 的单独表。

【讨论】:

  • 您的意思是从 BasePerson 继承 Student 和 Instructor 吗?否则我不明白这一点。
猜你喜欢
  • 2012-11-18
  • 2014-07-15
  • 2019-11-25
  • 2022-11-24
  • 2021-10-27
  • 1970-01-01
  • 2014-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多