繁体   English   中英

实体框架将实体映射到级联的多个表

[英]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”相关字段,但是由于两个原因,我不想这样做:

  1. 我在“购买”类中没有任何DbConnection可用,因此我无法创建DbCommand来从DB读取数据。
  2. 我希望实体类是持久性忽略的
  3. EF似乎是一个功能强大的工具,可以执行此类操作,并且我不想通过编写自定义过程来重新发明轮子。

我在此处上传了示例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() CustomerCustomersType

另一种选择是使用诸如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");
});

顺便说一句,您还应该删除CustomerCustomersType的映射配置类,它们是多余的。

但是,如上所述,数据库架构与所需的结构不匹配。 如果您尝试保存Purchase ,则将获得外键约束异常。 这是因为EF期望以下表结构:

在此处输入图片说明

其中列IdPurchaseCustomerCustomersType都是主键和外键Purchase 我认为这不是您在设计数据库时想到的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM