每个层级映射的代码优先表

本文关键字:代码 映射 | 更新日期: 2023-09-27 18:12:22

我有一个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时更容易(例如,只有OrganisationSupplier可以与采购订单相关联)。

我已经创建了两个从Organisation类派生的类。

public class Supplier : Organisation
{
}
public class Customer : Organisation
{
}

接下来我想告诉实体框架如何将这些类映射到表。所有信息都将存储在一个名为"组织"的表中,所以我试图使用TPH(每层次表)映射。

我希望我的映射是这样工作的:

  • 如果我查询Organisations,我希望实体框架返回所有组织,而不管IsCustomerIsSupplier属性中的值。
  • 如果我查询Suppliers,我希望实体框架返回所有组织,其中IsSupplier = true .
  • 如果我查询Customers,我希望实体框架返回所有组织,其中IsCustomer = true .

一个组织既是客户又是供应商是有效的,所以我希望一些组织同时包含在CustomerSupplier查询中。

下面是我定义的配置类:

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);
            });
    }
}

这将导致抛出DataException并伴有以下消息:

错误3032:从第59行开始的映射片段的问题:条件组织成员。IsSupplier’的条件不是映射'IsNull=False'。移除条件组织。

我不确定如何修复这个错误,或者即使我想做的是可能的,因为我所看到的所有例子都有一个鉴别器列。虽然我需要区分既是客户又是供应商的组织,但我不确定我是否能够通过单一的鉴别器实现我想要的结果。

更新:

经过一些研究,似乎错误是我在Organisation类中定义了IsSupplierIsCustomer属性的结果。如果我删除这些属性,那么我的数据库是正确构建的,我的映射工作(实体框架创建在我的表中单独的鉴别符)。

我已经用3个单独的查询(1选择Organisations, 1选择Customers和1选择Suppliers)测试了这一点,这似乎给了我正确的结果,所以这让我对我的解决方案的方式约90%。

我现在的问题是,我需要一种方法从数据库中选择一个Customer,也设置为供应商(因为我没有属性设置)。

每个层级映射的代码优先表

现在不能尝试,但我认为只允许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原则。一个实例不能有两个派生类型,c#不支持。

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


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

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

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

,您可以简单地将客户添加到公共实体集:

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

通常你不会在查询中使用Discriminator属性。