我在使用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个独立的实体。我想要一个与所有表相关的字段。 Customers和CustomersType表的所有字段必须是只读的(因此我设置相对的setter受保护),其他字段必须是可编辑的,以便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'被映射不止一次。确保 Properties方法仅指定每个非键属性一次。
也许有些错误或者我忘了某些东西(例如Map&lt;&gt;的连接字段,我不知道在哪里指定它们)。 我怎样才能以正确的方式完成这项任务? 我不希望在我的上下文中有“Customers”和“CustomersType”DBSets。 有没有办法避免它?
我甚至想在“IdCustomer”中添加一个自定义查询来手动更新“Customers”和“CustomersType”相关字段,但我不想这样做有两个原因:
我上传了示例C#source和表CREATE脚本(MS SQLServer)here。 所有实体都由“EF反向POCO生成器”T4模板自动生成(禁用T4模板,激活它设置CustomTool = TextTemplatingFileGenerator)。 不要忘记更新app.config中的ConnectionString。
提前致谢。
答案 0 :(得分:2)
我担心坏消息是这种表结构无法实现这种映射。您在此处尝试实现的内容称为实体拆分。但是,实体拆分需要1:1关联,因为所涉及的表中的记录集代表一个实体。使用此映射,您不能拥有属于多个Customer
的{{1}}。这意味着您可以通过修改其中一个Purchase
属性来修改多个Purchase
实体。
也许新闻不是那么糟糕,因为我认为你实际上想要有1-n关联。但是你不能在Customer
中拥有这些“扁平化”的属性。
作为替代方案,您可以创建委托属性,如下所示:
Purchase
获取public string CodCustomer
{
get { return this.Customer.CodCustomer; }
set { this.Customer.CodCustomer = value; }
}
时,您必须Include()
Customer
和CustomersType
。
另一种方法是使用AutoMapper之类的工具将Purchase
映射到具有展平属性的DTO类型。
您将Purchase
实体映射到Purchase
表。但是,您没有指定要映射到此表的属性。因此,EF假定应将所有属性映射到它。这是Purchases
的第一个(隐式)映射。第二个是CodCustomer
语句中的一个。 (EF仅报告第一个问题。)
要解决此问题,您应该为剩余的mc.ToTable
属性添加映射语句:
Purchase
顺便说一下,您还应该删除Map(mc =>
{
mc.Properties(n => new
{
n.IdPurchase,
n.CodPurchase,
n.IdCustomer,
n.Total,
});
mc.ToTable("Purchases");
});
和Customer
的映射配置类,它们是多余的。
但是,如上所述,数据库架构与所需的结构不匹配。如果您尝试保存CustomersType
,则会收到外键约束异常。这是因为EF期望以下表结构:
Purchase
和IdPurchase
中的列Customer
都是CustomersType
的主键和外键。我不认为这是您在设计数据库时的想法。