实体框架中的派生类型

dab*_*han 6 c# entity-relationship entity-framework relationship

我有一个PersonClass 和 Inventory 可以是两种类型:SalesCustomerService.

SalesCustomerService具有其独特的属性并Peron拥有共同的属性。我希望能够查询

那么,在创建所有三个类时,我如何在它们之间创建 EF 关系?或者有没有更好的方法来考虑类的划分?

我不想将 Person 作为抽象类,因为大多数时候我想查询公共属性。

小智 4

您可以在此处采取 3 种可能的方法:


1. 将所有类型存储在一个表中(每个层次结构表)

您将拥有一个Person类,其中包含三个类之间所需的所有可能的属性。此外,您还可以添加一个PersonType枚举来为每个条目指定不同的类型。

public class Person
{
    public int PersonId { get; set; }

    public string Name { get; set; }

    // ...

    public PersonType Type { get; set; }
}

public enum PersonType
{
    Sales,
    CustomerService
}
Run Code Online (Sandbox Code Playgroud)

这通常是最简单且性能最好的方法。最大的问题是专业领域。由于每种类型都在这个表中,因此该表需要包含任何类型可能需要的所有字段。这也意味着所有专用字段都需要可为空,这使得强制执行具有特定字段的特定类型变得困难。


2.将每种类型存储在单独的表中(Table per Concrete Class)

Person您可以只拥有简单地重复表中包含的属性的表,而不是根本拥有Sales表。CustomerServicePerson

public class Sales
{
    public int SalesId { get; set; }

    public string Name { get; set; }

    // ...
}

public class CustomerService
{
    public int CustomerServiceId { get; set; }

    public string Name { get set; }

    // ... 
}
Run Code Online (Sandbox Code Playgroud)

当然,如果您愿意,您仍然可以利用Person代码中的抽象。使用代码优先,您可以利用继承:

public class Person
{
    public string Name { get; set; }
}

public class Sales : Person
{
    public int SalesId { get; set; }

    // ...
}

public class CustomerService : Person
{
    public int CustomerServiceId { get; set; }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

只需确保您只为子类定义实体SalesCustomerServiceDbContext子类中定义实体:

public class MyContext : DbContext
{
    // Do not include a DbSet for Person.

    public DbSet<Sales> Sales { get; set; }

    public DbSet<CustomerService> CustomerService { get; set; }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是您的类型被分成清晰、不同的集合。缺点是没有简单的方法可以对每个“人”进行通用搜索,因为就数据库而言,这种抽象并不存在。例如,如果您想查找具有特定名称的某人,则必须手动对表SalesCustomerService表进行单独搜索,这可能并不理想。此外,如果您最终找到一个同时担任销售和客户服务角色的人员,那么您将造成冗余,因为您需要在两个条目中输入他们的信息。


3. 将每个类型和基类型存储在各自的表中(Table per Type)

在您的类之上Person,您还将创建Sales一个CustomerService类,每个类指定其专用属性并包含对该类的引用Person。这是一个常见的原则,称为组合优于继承;由于我们无法有效地对数据库中的继承进行建模,因此我们可以使用组合来代替。

public class Person
{
    public int PersonId { get; set; }

    public string Name { get; set; }

    // ...
}

public class Sales
{
    public int SalesId { get; set; }

    public int PersonId { get; set; }

    public virtual Person { get; set; }

    // ...
}

public class CustomerService
{
    public int CustomerServiceId { get; set; }

    public int PersonId { get; set; }

    public virtual Person { get; set; }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

这将允许您为每种类型添加专用属性,同时仍然维护Person可以搜索的通用表。如果某人担任多个角色,这也将允许您重复使用该人的信息。缺点是创建新Sales记录CustomerService有点乏味,因为您还需要查找现有Person记录或创建新记录。这也可能不是最好的性能,因为查询最终可能需要连接。


您应该采取的方法取决于您的需求。如果您想更深入地了解这 3 种策略,请查看本教程,了解如何在实体代码优先中实现继承:

http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx