[英]Entity framework map entity to multiple tables in cascade
我在使用EF时遇到问题。 我有以下情况:
我想从此数据库架构中通过合并表数据生成以下实体:
// Purchases
public class Purchase
{
//Fields related to Purchases
public int IdPurchase { get; set; }
public string CodPurchase { get; set; }
public int IdCustomer { get; set; }
public decimal Total { get; set; }
//Fields related to Customers table
public string CodCustomer { get; protected set; }
public string CompanyTitle { get; protected set; }
public string CodType { get; protected set; }
//Fields related to CustomersType table
public string DescrType { get; protected set; }
}
如您所见,在我的上下文中,我不希望每个表具有3个分离的实体。 我想要一个与所有表相关的字段。 客户表和客户类型表的所有字段都必须是只读的(因此我已将相对设置器设置为受保护的),其他字段必须是可编辑的,以便EF可以跟踪更改。 特别是,我希望能够更改“ IdCustomer”字段,并让EF通过执行交叉表选择来自动更新“ CodCustomer”,“ CompanyTitle”,“ DescrType” ...等等。
为此,我编写了以下配置类:
internal class PurchaseConfiguration : EntityTypeConfiguration<Purchase>
{
public PurchaseConfiguration(string schema = "dbo")
{
ToTable(schema + ".Purchases");
HasKey(x => x.IdPurchase);
Property(x => x.IdPurchase).HasColumnName("IdPurchase").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.IdCustomer).HasColumnName("IdCustomer").IsRequired();
Property(x => x.Total).HasColumnName("Total").IsRequired().HasPrecision(19, 4);
Map(mc =>
{
mc.Properties(n => new
{
n.CodCustomer,
n.CompanyTitle,
n.CodType
});
mc.ToTable("Customers");
});
Map(mc =>
{
mc.Properties(n => new
{
n.DescrType,
});
mc.ToTable("CustomersType");
});
}
}
我已经对其进行了测试,但是无法正常工作。 我总是收到此消息:
“购买”类型的属性只能映射一次。 非关键属性“ CodCustomer”被映射多次。 确保“属性”方法仅指定每个非关键属性一次。
也许出了点问题,或者我忘记了一些东西(例如,我不知道在哪里指定的Map <>的联接字段)。 我如何正确完成此任务? 我不想在上下文中包含“ Customers”和“ CustomersType” DBSet。 有办法避免吗?
我什至考虑将自定义查询添加到“ IdCustomer” setter中,以手动更新“ Customers”和“ CustomersType”相关字段,但是由于两个原因,我不想这样做:
我在此处上传了示例C#源代码和表CREATE脚本(MS SQLServer)。 所有实体均由“ EF反向POCO生成器” T4模板自动生成(禁用T4模板,可通过设置CustomTool = TextTemplatingFileGenerator来激活它)。 不要忘记在app.config中更新ConnectionString。
提前致谢。
恐怕坏消息是此表结构无法实现此映射。 您要在此处实现的目标称为实体拆分 。 但是,实体拆分需要1:1关联,因为所涉及表中的记录集代表一个实体。 使用此映射,您不能拥有一个Customer
属于多个Purchase
。 这意味着您可以通过仅修改其中一个的“ Customer
属性来修改多个“ Purchase
实体。
也许这个消息并不是那么糟糕,因为我认为您实际上想拥有1-n关联。 但是,那么在Purchase
就不能拥有这些“扁平化”的属性。
另外,您可以创建委托属性,如下所示:
public string CodCustomer
{
get { return this.Customer.CodCustomer; }
set { this.Customer.CodCustomer = value; }
}
在获取Purchase
时,必须Include()
Customer
和CustomersType
。
另一种选择是使用诸如AutoMapper的工具将Purchase
映射到具有扁平属性的DTO类型。
您将Purchase
实体映射到Purchases
表。 但是,您没有指定要映射到该表的属性。 因此,EF假定所有属性都应映射到它。 这就是CodCustomer
的第一个(隐式)映射。 第二个是mc.ToTable
语句中的一个。 (EF仅报告第一个问题。)
要解决此问题,您应该为剩余的Purchase
属性添加一个映射语句:
Map(mc =>
{
mc.Properties(n => new
{
n.IdPurchase,
n.CodPurchase,
n.IdCustomer,
n.Total,
});
mc.ToTable("Purchases");
});
顺便说一句,您还应该删除Customer
和CustomersType
的映射配置类,它们是多余的。
但是,如上所述,数据库架构与所需的结构不匹配。 如果您尝试保存Purchase
,则将获得外键约束异常。 这是因为EF期望以下表结构:
其中列IdPurchase
在Customer
和CustomersType
都是主键和外键Purchase
。 我认为这不是您在设计数据库时想到的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.