【问题标题】:Table per Hierarchy table mapping with both shared and unshared columns具有共享列和非共享列的每个层次结构表映射
【发布时间】:2014-11-13 03:31:41
【问题描述】:

这是this question 的扩展,据我所知,它现在可以在 EF6 中使用。但是,当您的子类同时具有共享和非共享属性时,似乎会出现问题。

假设这是我的模型设置:

public abstract class Document
{
    public int Id { get; set; }
    public string NameOnDocument { get; set; }
}

public class BirthCertificate : Document
{
    public string RegistrationNumber { get; set; }
}

public class Licence : Document
{
    public string LicenceNumber { get; set; }
}

在数据库中,我希望BirthCertificate.RegistrationNumberLicence.LicenceNumber 共享同一列Number。因此,我正在这样设置我的模型:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // Document - base class
    modelBuilder.Entity<Document>().HasKey(d => d.Id);
    modelBuilder.Entity<Document>()
        .Property(d => d.Id)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    modelBuilder.Entity<Document>()
        .Property(d => d.NameOnDocument)
        .HasColumnName("Name");

    // Birth certificate
    modelBuilder.Entity<Document>().Map<BirthCertificate>(map => 
        map.Property(c => c.RegistrationNumber).HasColumnName("Number"));

    // Licence
    modelBuilder.Entity<Document>().Map<Licence>(map => 
        map.Property(l => l.LicenceNumber).HasColumnName("Number"));
}

当我生成数据库时,一切看起来和工作正常:

现在讨论手头的问题。假设Licence 实体也需要记录到期日期;所以我将其添加如下:

public class Licence : Document
{
    public string LicenceNumber { get; set; }
    public DateTime ExpiryDate { get; set; }
}

现在当我重新生成数据库时,它看起来像这样:

此外,如果我尝试插入许可证和出生证明,我会收到以下异常:

EntityFramework.dll 中出现“System.Data.Entity.Infrastructure.DbUpdateException”类型的未处理异常

附加信息:在多个位置生成跨实体或关联共享的值。检查映射是否不会将 EntityKey 拆分为多个存储生成的列。

我可以理解为什么会引发该异常 - 因为数据库没用。

我错过了什么?

【问题讨论】:

    标签: c# sql-server entity-framework entity-framework-6 table-per-hierarchy


    【解决方案1】:

    好的,事实证明问题很容易解决,但据我所知,在任何地方都没有记录。所以希望这能帮助遇到同样问题的人。

    看起来,关键是你必须在派生实体上映射每个属性

    modelBuilder.Entity<Document>().Map<Licence>(map =>
    {
        map.Property(l => l.LicenceNumber).HasColumnName("Number");
        map.Property(l => l.ExpiryDate).HasColumnName("ExpiryDate");
    });
    

    现在我的数据库按预期生成,一切正常。

    【讨论】:

      【解决方案2】:

      我不确定通过将 2 列放入数据库中的 1 列会获得多少。我认为您不会节省太多空间,并且您无法询问基础DocumentNumber,即使两个文档都有一个。您是否考虑过将 Number 字段添加到基础并在覆盖上使用数据注释 - 像这样?

      public abstract class Document
      {
          public int Id { get; set; }
          public string NameOnDocument { get; set; }
          public virtual string Number
      }
      
      public class BirthCertificate : Document
      {
          [Display(Name="Registration Number"]
          [Required]
          public override string Number { get; set; }
      }
      
      public class Licence : Document
      {
          [Display(Name="Licence Number"]
          [Required]
          public override string Number { get; set; }
      }
      

      编辑如果所有文档都没有编号:

      public abstract class Document
      {
          public int Id { get; set; }
          public string NameOnDocument { get; set; }
      }
      
      public abstract class NumberedDocument : Document
      {
          public virtual string Number
      }
      
      public class BirthCertificate : NumberedDocument
      {
          [Display(Name="Registration Number"]
          [Required]
          public override string Number { get; set; }
      }
      

      【讨论】:

      • 虽然这是一个更大问题的精简示例...实际上大约有 6 种文档类型,每种类型共享大约 5 个公共属性以及一些半公共属性。并非所有文件都有编号。不过感谢您的建议。
      • @gerrod 编辑以展示如何将继承用于“半通用”属性
      • 谢谢;但这仍然太简单了:-)。它更像 - 结合公共属性,我的表有七个可能共享的属性 - PropertyA、PropertyB.... PropertyG。 Document1 具有 PropertyA、PropertyC。 Document2 具有 PropertyC、PropertyE、PropertyF。 Document3 有 PropertyB、PropertyE、PropertyG。 etc etc 六种不同的文档类型,每一种都有不同的共享属性组合。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-22
      • 2021-09-25
      • 1970-01-01
      • 2012-09-06
      相关资源
      最近更新 更多