【问题标题】:Entity Framework - Modeling multiple roles for same entity实体框架 - 为同一实体建模多个角色
【发布时间】:2016-04-13 05:54:59
【问题描述】:

我有一个联系人类

[Table("Contacts")]
public class Contact
{
    public string Id { get; set; }
    public string Name { get; set; }
}

我有两个继承自 Contact 的类:

[Table("Employees")]
public class Employee : Contact
{
    public decimal Salary { get; set; }
}

[Table("Suppliers")]
public class Supplier : Contact
{
    public string TIN { get; set; }
}

我使用 Entity Framework 6.3 作为我的 ORM。

我可以模拟一些相同的联系人既可以是 Employee 又可以是 Employee 和 具有相同唯一 ID 的供应商。

Employee emp = new Employee();
emp.Id = "C1";
emp.Name = "Employees";
emp.Salary = 10000;
emp.TrackingState = TrackingState.Added;

Supplier sup = new Supplier();
sup.Id = "C1";
sup.Name = "Employees";
sup.TIN = "ABC";
sup.TrackingState = TrackingState.Added;

当我这样做时:

context.Employee.Add(emp);
context.Supplier.Add(sup);
context.Save();

显然,它不允许我添加记录。 我收到一个错误:

“违反 PRIMARY KEY 约束 'PK_dbo.Contacts'。无法在对象 'dbo.Contacts' 中插入重复键。重复键值为 (C1)。\r\n语句已终止。”

我可以让供应商也与员工共享相同的 ID,并且 启用员工和供应商的插入/更新?

谢谢

【问题讨论】:

    标签: entity-framework-6 domain-model


    【解决方案1】:

    我假设您没有进行任何特定的继承映射,默认情况下会将其映射为 Table per Hierarchy (TPH) 继承。使用此映射,您将获得一个 Db 表,其中包含基类型中所有字段的聚合以及具有鉴别器字段的依赖类型,以了解应具体化行的类型。这允许在您要求类型的地方进行查询。

    使用 TPH,每行只能是一种类型,因此您不能让同一行既是员工又是供应商。

    您可以执行另一种类型的映射,称为每个类型的表 (TPT),它将为每种类型创建一个表,因此在您的情况 3 中,一个用于共享字段,一个用于每个依赖类型。这应该考虑到您要问的问题。 (YMMV)

    但是,Employee 和 Supplier 似乎会在很多不同的领域中使用,所以我建议您创建您的 Contact 表并将其与您的员工和供应商相关联。

    [Table("Contacts")]
    public class Contact
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }
    
    [Table("Employees")]
    public class Employee
    {
        public string Id { get; set; }
        public string ContactId { get; set; }
        public decimal Salary { get; set; }
    
        public Contact Contact { get; set; }
    }
    
    [Table("Suppliers")]
    public class Supplier
    {
        public string Id { get; set; }
        public string ContactId { get; set; }
        public string TIN { get; set; }
    
        public Contact Contact { get; set; }
    }
    

    现在您可以查询员工了:

    db.Employees.Include(e => e.Contact).First();
    

    或者对于供应商:

    db.Employees.Include(e => e.Contact).First();
    

    这可能比您需要的继承查询更干净:

    db.Contacts.OfType<Employee>().First();
    

    在上面显示的 Has A 建模和 Is A Modeling with TPT 中,您将获得三个表。您只是在我显示的内容中使用 FK,而不是在 3 个带有 TPT 的表中使用相同的 ID。

    您还可以查看每个类的表,它类似于 TPT,但您没有获得抽象/父类的表,而是获得每个依赖类型的表,其中包含所有字段。我不认为这是你想要的,因为它会有重复的数据,但是,它确实意味着更少的连接。

    【讨论】:

    • 谢谢。这看起来非常好。但是有没有可能通过 IsA 关系来实现这一点。
    • 正如我所说,使用 TPT 或 TPC 映射,您应该能够拥有与这两种类型相同的 Id。但是,我认为您确实在与框架作斗争。
    • 谢谢。我用 TPT 映射试过这个。我收到上面帖子中提到的错误。
    • 对,因为它认为您添加了一个新实体,因此它希望为每个依赖实体类型的联系人添加一行。
    猜你喜欢
    • 1970-01-01
    • 2016-10-16
    • 2010-11-28
    • 2023-04-01
    • 2018-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多