2012-01-18 67 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,原始列可用作外键。