我有一个
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; }
}
我创建了名为
Customer
和 Supplier
的组织子类,因为这将使在我的域的其他部分中使用 Organisations
时变得更容易(例如,只有作为 Organisation
的 Supplier
才可以与采购订单关联)。
我创建了两个派生自
Organisation
类的类。
public class Supplier : Organisation
{
}
public class Customer : Organisation
{
}
接下来我想告诉实体框架如何将这些类映射到表。所有信息都将存储在一个名为“组织”的表中,因此我尝试使用 TPH(每个层次结构表)映射。
这是我希望我的映射如何工作:
Organisations
,我希望实体框架返回所有组织,无论 IsCustomer
和 IsSupplier
属性中的值如何。Suppliers
,我希望实体框架返回 IsSupplier = true
所在的所有组织。Customers
,我希望实体框架返回 IsCustomer = true
所在的所有组织。组织既是客户又是供应商是有效的,因此我希望某些组织同时包含在
Customer
和 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);
});
}
}
这会导致抛出
DataException
并显示以下消息:
错误 3032:从第 59 行开始映射片段时出现问题:条件 成员“Organization.IsSupplier”的条件不是 'IsNull=False' 已映射。要么删除条件 Organization.IsSupplier 或将其从映射中删除。
我不确定如何修复此错误,或者即使我想做的事情是可能的,因为我看到的所有示例都有一个鉴别器列。我不确定我是否能够通过单个鉴别器实现我想要的结果,因为我需要区分既是客户又是供应商的组织。
更新:
经过一些研究,似乎错误是由于我在
IsSupplier
类中定义了 IsCustomer
和 Organisation
属性造成的。如果我删除这些属性,那么我的数据库将正确构建,并且我的映射可以正常工作(实体框架在我的表中创建单独的鉴别器)。
我已经用 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);
});
您当然应该定义一个枚举来替换 int。
你已经明白了,但是
一个组织既是客户又是供应商是有效的
....
因为我需要区分既是客户又是供应商的组织。
这完全违背了这里的基本 OOP 原则。一个实例不能有 2 个派生类型,C# 不支持这一点。
如果你想实现这一点,你需要一个完全不同的设计。
我需要一种从数据库中选择客户并将其设置为客户的方法(因为我没有要设置的属性)。
您可以使用
OfType<>
方法选择客户或供应商:
IEnumerable<Customer> allCustomers = myContext.Organisations.OfType<Customer>();
您可以简单地将客户添加到通用实体集中:
var c = new Customer(....);
myContext.Organisations.Add(c);
一般来说,您不会在查询中使用鉴别器属性。
对我来说,错误 3032 的解决方案是将
[NotMapped]
添加到我的鉴别器属性