1

我有一个问题,当使用抽象类时将外键映射到正确的表。这里是我的模型:使用抽象类和流利的API时错位的外键

public abstract class Entity 
{ 
    public Guid UID { get; set; } 
} 

public abstract class Product : Entity 
{ 
    public DeviceModel Model { get; set; } 
    public User Operator { get; set; } 
} 

public abstract class OrderEntry : Entity 
{ 
    public Order Order { get; set; } 
} 

public class Device : Product 
{ 
    public String Reference { get; set; } 
    public String Serial { get; set; } 
    public String SoftwareVersion { get; set; } 
} 

public class OrderEntryDevice : OrderEntry 
{ 
    public DeviceModel Model { get; set; } 
} 

而流畅API配置(TPT模式):

public class EntityConfiguration : EntityTypeConfiguration<Entity> 
{ 
    public EntityConfiguration() 
    { 
     ToTable("Entities"); 

     HasKey(t => t.UID); 
    } 
} 

public class ProductConfiguration : EntityTypeConfiguration<Product> 
{ 
    public ProductConfiguration() 
    { 
     ToTable("Products"); 

     HasOptional(t => t.Operator) 
      .WithMany() 
      .Map(t => t.MapKey("FK_Operator")) 
      .WillCascadeOnDelete(false); 
    } 
} 

public class OrderEntryConfiguration : EntityTypeConfiguration<OrderEntry> 
{ 
    public OrderEntryConfiguration() 
    { 
     ToTable("OrderEntries"); 

     HasRequired(t => t.Order) 
      .WithMany() 
      .Map(t => t.MapKey("FK_Order")) 
      .WillCascadeOnDelete(false); 
    } 
} 

public class DeviceConfiguration : EntityTypeConfiguration<Device> 
{ 
    public DeviceConfiguration() 
    { 
     ToTable("Devices"); 

     Property(t => t.Reference) 
      .IsRequired(); 

     Property(t => t.Serial) 
      .IsRequired(); 

     HasRequired(t => t.Model) 
      .WithMany() 
      .Map(t => t.MapKey("FK_Model")) 
      .WillCascadeOnDelete(false); 
    } 
} 

public class OrderEntryDeviceConfiguration : EntityTypeConfiguration<OrderEntryDevice> 
{ 
    public OrderEntryDeviceConfiguration() 
    { 
     ToTable("OrderEntriesDevice"); 

     HasRequired(t => t.Model) 
      .WithMany() 
      .Map(t => t.MapKey("FK_Model")) 
      .WillCascadeOnDelete(false); 
    } 
} 

数据库将把“FK_Operator”外键中的“产品”表(正是创作我想要它)但“FK_Order”外键放置在“实体”表中,而不是“OrderEntries”表中。如果我将类“OrderEntry”的抽象属性更改为具体,那么一切都正常。在这种情况下,我是否必须避免抽象类?

回答

0

我试过你的模型,我不能重现这个问题。我得到OrderEntries表中的FK_Order列,而不是在Entities表中 - 正如所料。

您可以将以下内容复制到控制台应用程序的Program.cs(也可将EntityFramework.dllSystem.ComponentModel.DataAnnotations.dll添加到引用中)。

我已经为UserDeviceModelOrder创建了三个虚拟类来获取代码编译和运行。但其他课程是您的问题的副本。

现在的问题是:下面的代码和你的代码之间的重要区别在哪里,可能导致你有错误的映射?

using System; 
using System.Linq; 
using System.Data.Entity.ModelConfiguration; 
using System.Data.Entity; 
using System.ComponentModel.DataAnnotations; 

namespace EFAbstractTest 
{ 
    public class User 
    { 
     [Key] 
     public Guid UID { get; set; } 
     public string Name { get; set; } 
    } 

    public class DeviceModel 
    { 
     [Key] 
     public Guid UID { get; set; } 
     public string Name { get; set; } 
    } 

    public class Order 
    { 
     [Key] 
     public Guid UID { get; set; } 
     public string Name { get; set; } 
    } 

    public abstract class Entity 
    { 
     public Guid UID { get; set; } 
    } 

    public abstract class Product : Entity 
    { 
     public DeviceModel Model { get; set; } 
     public User Operator { get; set; } 
    } 

    public abstract class OrderEntry : Entity 
    { 
     public Order Order { get; set; } 
    } 

    public class Device : Product 
    { 
     public String Reference { get; set; } 
     public String Serial { get; set; } 
     public String SoftwareVersion { get; set; } 
    } 

    public class OrderEntryDevice : OrderEntry 
    { 
     public DeviceModel Model { get; set; } 
    } 

    public class EntityConfiguration : EntityTypeConfiguration<Entity> 
    { 
     public EntityConfiguration() 
     { 
      ToTable("Entities"); 

      HasKey(t => t.UID); 
     } 
    } 

    public class ProductConfiguration : EntityTypeConfiguration<Product> 
    { 
     public ProductConfiguration() 
     { 
      ToTable("Products"); 

      HasOptional(t => t.Operator) 
       .WithMany() 
       .Map(t => t.MapKey("FK_Operator")) 
       .WillCascadeOnDelete(false); 
     } 
    } 

    public class OrderEntryConfiguration : EntityTypeConfiguration<OrderEntry> 
    { 
     public OrderEntryConfiguration() 
     { 
      ToTable("OrderEntries"); 

      HasRequired(t => t.Order) 
       .WithMany() 
       .Map(t => t.MapKey("FK_Order")) 
       .WillCascadeOnDelete(false); 
     } 
    } 

    public class DeviceConfiguration : EntityTypeConfiguration<Device> 
    { 
     public DeviceConfiguration() 
     { 
      ToTable("Devices"); 

      Property(t => t.Reference) 
       .IsRequired(); 

      Property(t => t.Serial) 
       .IsRequired(); 

      HasRequired(t => t.Model) 
       .WithMany() 
       .Map(t => t.MapKey("FK_Model")) 
       .WillCascadeOnDelete(false); 
     } 
    } 

    public class OrderEntryDeviceConfiguration : EntityTypeConfiguration<OrderEntryDevice> 
    { 
     public OrderEntryDeviceConfiguration() 
     { 
      ToTable("OrderEntriesDevice"); 

      HasRequired(t => t.Model) 
       .WithMany() 
       .Map(t => t.MapKey("FK_Model")) 
       .WillCascadeOnDelete(false); 
     } 
    } 

    public class MyContext : DbContext 
    { 
     public DbSet<Entity> Entities { get; set; } 
     public DbSet<User> Users { get; set; } 
     public DbSet<DeviceModel> DeviceModels { get; set; } 
     public DbSet<Order> Orders { get; set; } 

     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      modelBuilder.Configurations.Add(new EntityConfiguration()); 
      modelBuilder.Configurations.Add(new ProductConfiguration()); 
      modelBuilder.Configurations.Add(new OrderEntryConfiguration()); 
      modelBuilder.Configurations.Add(new DeviceConfiguration()); 
      modelBuilder.Configurations.Add(new OrderEntryDeviceConfiguration()); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (var ctx = new MyContext()) 
      { 
       // some query, just to trigger database creation 
       ctx.Orders.Count(); 
      } 
     } 
    } 
} 
+0

感谢您的回复。你的上下文和我的上下文之间唯一的巨大差异可以在你定义的dbset中找到:我只定义了实体dbset,而不是其他的。我会尽快在我恢复工作时添加一些dbset。 – Glopper

+0

好吧,似乎为每个抽象类创建一个dbset就是解决方案。否则,我假设使用“ToTable”的映射将通过继承层次结构,直到他找到具有相应dbset的第一个抽象类。我将你的帖子标记为答案,再次感谢。 – Glopper