2012-01-18 68 views
3

我的數據庫中有兩個表。一個叫Users,另一個叫WidgetsWidgets表代表我的代碼模型中的3個實體。其中一個實體Widget是其他兩個實體的父級,WidgetTypeAWidgetTypeBWidgetTypeAWidgetTypeB都對用戶實體具有導航屬性,該用戶實體持久保存到數據庫的用戶表中。我無法讓Code First爲WidgetTypeAWidgetTypeB實體(UserId)使用相同的外鍵。有誰知道如何做到這一點?它似乎應該是表每個層次結構映射的常見問題。關於EF代碼的困難首先流利的API,TPH和外鍵

我的實體類如下:

public class Widget 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 
} 

class WidgetMap : EntityTypeConfiguration<Widget> 
{ 
    public WidgetMap() 
    { 
     ToTable("Widgets"); 

     HasKey(w => w.Id); 
     Property(w => w.Id) 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

     Property(w => w.Name) 
      .IsRequired() 
      .HasMaxLength(75) 
      .IsUnicode(true); 
    } 
} 

public class WidgetTypeA : Widget 
{ 
    public int UserId { get; set; } 
    public virtual User User { get; set; } 

    public string Color { get; set; } 
    public int DepthLevel { get; set; } 
} 

class WidgetTypeAMap : EntityTypeConfiguration<WidgetTypeA> 
{ 
    public WidgetTypeAMap() 
    { 
     Map(w => w.Requires("WidgetTypeId").HasValue(1)); 

     HasRequired(w => w.User) 
      .WithMany(u => u.WidgetTypeAs) 
      .HasForeignKey(w => w.UserId) 
      .WillCascadeOnDelete(false); 

     Property(w => w.Color) 
      .IsOptional() 
      .IsUnicode(true) 
      .HasMaxLength(75); 

     Property(w => w.DepthLevel) 
      .IsOptional(); 
    } 
} 

public class WidgetTypeB : Widget 
{ 
    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

class WidgetTypeBMap : EntityTypeConfiguration<WidgetTypeB> 
{ 
    public WidgetTypeBMap() 
    { 
     Map(w => w.Requires("WidgetTypeId").HasValue(2)); 

     HasRequired(w => w.User) 
      .WithMany(u => u.WidgetTypeBs) 
      .HasForeignKey(w => w.UserId) 
      .WillCascadeOnDelete(false); 
    } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public string Username { get; set; } 
    public int Age { get; set; } 

    public virtual ICollection<WidgetTypeA> WidgetTypeAs { get; set; } 
    public virtual ICollection<WidgetTypeB> WidgetTypeBs { get; set; } 
} 

class UserMap : EntityTypeConfiguration<User> 
{ 
    public UserMap() 
    { 
     ToTable("Users"); 

     HasKey(u => u.Id); 

     Property(u => u.Username) 
      .IsRequired() 
      .HasMaxLength(75) 
      .IsUnicode(true); 

     Property(u => u.Age) 
      .IsRequired(); 
    } 
} 

無論如何,我不斷收到錯誤

無效的列名稱UserId1「

,當我嘗試執行以下操作:

using (var entities = new MyEntities()) 
{ 
    User u = new User 
    { 
     Username = "Frank", 
     Age = 14 
    }; 
    entities.Users.Add(u); 
    entities.SaveChanges(); 

    WidgetTypeA wa1 = new WidgetTypeA 
    { 
     Name = "0SDF81", 
     UserId = u.Id, 
     DepthLevel = 6 
    }; 
    entities.WidgetTypeAs.Add(wa1); 
    entities.SaveChanges(); 
} 

不確定這是否可以修復。我總是可以爲Widgets表指定第二個UserId外鍵,但這似乎毫無意義。也許有一種方法可以使用Fluent API來做到這一點?

回答

2

您不能將在不同派生實體中定義的屬性映射到同一列。這是EF中的限制。如果您的WidgetTypeA擁有UserId屬性,而您的WidgetTypeB擁有UserId屬性,則它們必須是數據庫中的不同列。如果將UserIdUser屬性從派生類型移動到父類型Widget類型,它應該可以工作。

0

我知道它很晚了,但希望可以幫助其他讀者。

儘管Ladislav在EF6中不支持使用映射的外鍵是正確的,但我確實找到了一種有用的解決方法。

可以定義一個計算列規範,其表達式只需引用原始列。以上描述中的Userid。這可以用作TPH映射的鑑別器。採用這種方法,該列無需持久化,但可用於TPH,原始列可用作外鍵。