我正在使用EntityFramework(代码优先)设计数据输入应用程序来收集客户详细信息。
所需的数据结构很简单。
客户实体有一些扁平和一对多的详细信息(例如姓名,电话号码等),然后是大量的多对多属性,这些属性始终遵循相同的模式,允许多种选择一个列表(在UI中,这将显示为一个复选框列表),用户也可以添加项目。对于这些多选属性中的每一个,还有一个Notes属性,允许用户解释为什么这些详细信息与客户连接(换句话说,这只是Customer实体中的字符串)。
由于这些属性的相似性和数据的相对简单性,我开始寻求使用继承进行建模,但我现在认为可能有更好的方法来实现这一点,特别是因为如果system允许管理员用户动态添加此类型的新属性。
我正在寻找任何建议来实现这一点,而无需手动定义和连接所有实体,或至少最大限度地减少执行此操作所需的代码量。
答案 0 :(得分:1)
SQL不知道继承的概念。但是,有几种策略可以让实体框架接受您继承的类。您应该使用哪种策略取决于您最常询问的查询类型。
假设您有两个班级Student
和Teacher
。这两个类都有很多共同的属性(可能还有方法)。您想将它们放在基类中:Person
。您不希望能够创建Person
对象,因此您的Person
类将是抽象的。
在C#中:
abstract class Person
{
... // common person properties
}
class Teacher : Person
{
public int Id {get; set;} // Primary Key
... // Teacher properties
}
class Student : Person
{
public int Id {get; set;} // Primary Key
... // Student properties
}
您不打算仅Person
和Teachers
创建Students
个对象。因此,您可以创建Teachers
表和Students
表。 Teachers
表包含所有Teacher
属性以及所有Person
属性。同样,Student
表包含Student
属性和所有Person
属性。对于每个具体(=非抽象)类,您都可以创建一个表。
此策略称为Table-Per-Concrete-Class (TPC)。它与组合非常相似:教师'拥有'人物属性,而不是继承人物属性。它遵循旧的adagium“Favour composition over inheritance”
您可以在DbContext
class MyDbContext : DbContext
{
public DbSet<Student> Students {get; set;}
public DbSet<Teacher> Teachers {get; set;}
// we don't want a Person table, so no DbSet<Person>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Tell entity framework that the Teacher Table will include Person properties
modelBuilder.Entity<Teacher>().Map(m =>
{
m.MapInheritedProperties();
});
// Tell entity framework that the Student table will include Person properties
modelBuilder.Entity<Student>().Map(m =>
{
m.MapInheritedProperties();
});
}
}
查询“给我所有教师......”或“给我这些学生......”将涉及一张桌子。但是,如果你问:“给我所有的人......”将要求连续两张桌子。
var result = myDbContext.Teachers.Cast<Person>()
.Concat(myDbContext.Students.Cast<Person>())
.Where(person => ... // something with Person properties)
.Select(person => ... // something with Person properties);
每当我需要建模继承时,我大多数时候都会使用这种TPC策略。
如果您认为Persons
{而非Teachers
代替Person
,那么请考虑使用Table Per Type (TPT)
在TPT中,您将拥有三个表:一个Person
表,包含所有Teacher
属性,一个Teacher
表,其中包含Person
属性和一个外键,此Teacher
的{{1}}属性。类似地,您将拥有一个Student
表,其中包含其继承的Person
属性的外键。
要求“所有人......”只涉及一张桌子,无论该人是学生还是教师。因为你要求人,你不需要任何学生属性。
要求“所有教师......”将始终涉及两个表,即获取教师属性的教师表和访问人物属性的人员表。
因此,如果您经常询问“那些......的人”,那么对于“......的教师”,请考虑使用TPT。