每个层次结构映射的Code First表

时间:2013-05-07 12:19:45

标签: c# entity-framework ef-code-first

我有一个Organisation实体,代表可以是供应商客户两者的商家。

该实体如下所示:

public abstract class Organisation
{
    public Organisation()
    {
        IsCustomer = false;
        IsSupplier = false;
    }

    public int Id { get; set; }
    public string Name { get; set; }

    public bool IsSupplier { get; set; }
    public bool IsCustomer { get; set; }
}

我创建了名为CustomerSupplier的组织子类,因为在我的域的其他部分使用Organisations时,这将使事情变得更容易(仅限{{1}这是一个Organisation可以与采购订单相关联。)

我创建了两个派生自Supplier类的类。

Organisation

接下来,我想告诉Entity Framework如何将这些类映射到表中。所有信息都将存储在一个名为“组织”的表中,因此我尝试使用TPH(每个层次的表)映射。

以下是我希望我的映射工作的方式:

  • 如果我查询public class Supplier : Organisation { } public class Customer : Organisation { } ,我希望Entity Framework返回所有组织,而不管OrganisationsIsCustomer属性中的值。
  • 如果我查询IsSupplier,我希望实体框架返回Suppliers所有组织。
  • 如果我查询IsSupplier = true,我希望实体框架返回Customers所有组织。

组织同时兼顾客户和供应商是有效的,因此我希望某些组织可以包含在IsCustomer = trueCustomer个查询中。

这是我定义的配置类:

Supplier

这会导致class OrganisationConfiguration : EntityTypeConfiguration<Organisation> { internal OrganisationConfiguration() { ToTable("Organisations"); HasKey(o => o.Id); Map<Customer>(m => { m.Requires("IsCustomer").HasValue(true); }); Map<Supplier>(m => { m.Requires("IsSupplier").HasValue(true); }); } } 被抛出,并显示以下消息:

  

错误3032:从第59行开始映射片段的问题:条件   会员'Organisation.IsSupplier'的条件不是   'IsNull = False'被映射。要么删除条件   Organisation.IsSupplier或将其从映射中删除。

我不确定如何修复此错误,或者即使我想要做的事情是可能的,因为我看到的所有示例都有一个鉴别器列。我不确定我是否能够通过一个鉴别器实现我想要的结果,因为我需要区分同时是客户和供应商的组织。

更新

经过一些研究后,似乎错误是由于我在DataException课程中定义了IsSupplierIsCustomer属性。如果我删除这些属性,那么我的数据库正确构建并且我的映射有效(实体框架在我的表中创建单独的鉴别符)。

我已经使用3个单独的查询进行了测试(1个用于选择Organisation,1个用于选择Organisations,1个用于选择Customers),这似乎可以让我得到正确的结果我的解决方案占了90%左右。

我现在遇到的问题是我需要一种从数据库中选择Suppliers的方法,并且还设置为供应商(因为我没有要设置的属性)。

1 个答案:

答案 0 :(得分:1)

目前无法尝试,但我认为只允许使用1个鉴别列。

<击>
public abstract class Organisation
{
    ...
    //public bool IsSupplier { get; set; }
    //public bool IsCustomer { get; set; }
    public int SubType { get; set; }
}

   Map<Customer>(m =>
        {
            m.Requires("SubType").HasValue<int>(1);
        });

   Map<Supplier>(m =>
        {
            m.Requires("SubType").HasValue<int>(2);
        });

你当然应该定义一个enum来替换int。


你已经知道了,但是

  

组织既是客户又是供应商,这是有效的   ....
  因为我需要区分既是客户又是供应商的组织。

这完全违背了基本的OOP原则。实例不能是2种派生类型,在C#中不支持。

如果你想实现这个,你需要一个完全不同的设计。


  

我需要一种方法从数据库中选择一个客户,并且还设置为客户(因为我没有要设置的属性)。

您可以使用OfType<>方法选择客户或供应商:

 IEnumerable<Customer> allCustomers = myContext.Organisations.OfType<Customer>();

您只需将客户添加到公共实体集:

var c = new Customer(....);
myContext.Organisations.Add(c);

通常,您不在查询中使用Discriminator属性。