在EF6中建模外键的复合键(建模为实体引用)

时间:2014-07-10 09:56:15

标签: entity-framework nhibernate entity-framework-6

我来自nHibernate,我正在尝试创建一个具有2列复合键的实体,其中两列也是外键。

例如,我有一个UserRole表(UserId Guid,RoleId Guid)。我希望将其建模为

public class UserRole
{
  public User User { get; set; }
  public Role Role { get; set; }
}
但是EF似乎并不喜欢这个想法。我似乎还希望我添加Guid UserId {get;set;}Guid RoleId { get; set; }。我设法解决这个问题,通过在dbcontext中定义模型来处理FK部分,如下所示:

        modelBuilder.Entity<UserRole>()
            .HasRequired(x => x.Role)
            .WithRequiredPrincipal()
            .Map(x => x.MapKey("RoleId"));

        modelBuilder.Entity<UserRole>()
            .HasRequired(x => x.User)
            .WithRequiredPrincipal()
            .Map(x => x.MapKey("UserId"));

我希望我能成为一个会议。但是,当我试图这样做时:

modelBuilder.Entity<UserRole>().HasKey(x => new { x.User, x.Role });

它在运行时通过以下方式解决:

The property 'User' cannot be used as a key property on the entity 'Paroxysm.Domain.UserRole' because the property type is not a valid key type. Only scalar types, string and byte[] are supported key types.

仅供参考,这是在nHibernate byCode映射中完成的(稍微不同的例子):

public class ProjectUserProfileMap : ClassMap<ProjectUserProfile>
{
    public ProjectUserProfileMap()
    {
        CompositeId()
            .KeyReference(x => x.User, "UserId")
            .KeyReference(x => x.Project, "ProjectId");

        ReadOnly();

        References(x => x.User, "UserId");
        References(x => x.Project, "ProjectId");

        Map(x => x.IsActive);
        Map(x => x.ActivatedUtcDate).Not.Nullable().CustomType<NHibernate.Type.UtcDateTimeType>();
        Map(x => x.InvitedUtcDate).Not.Nullable().CustomType<NHibernate.Type.UtcDateTimeType>();

        Table("ProjectUserProfile");
    }
}

太容易了!顺便提一下,EF似乎也不支持很少的CustomType UTC行为。

问题实际上与我有一个复合键这个事实无关,但是有一个单独的PK,也是一个FK,这将是一个奇怪的情况(1:1 rel)。

所以我想我想知道这是否可以在EF6中完成。错误消息肯定表明它不可行。有人可以证实吗?

1 个答案:

答案 0 :(得分:0)

只有添加到UserRole 2外键属性:RoleId和UserId,才能实现此目的。这是因为HasKey不提供任何映射功能 - 它只能在实体类中存在的属性上定义。似乎EF强制所有主键列始终被定义为类中的具体属性,因为外键列可能没有定义相应的属性。所以要实现你想要的东西你需要像这样定义UserRole:

public class UserRole
{
    public User User { get; set; }
    public int UserId { get; set; }
    public Role Role { get; set; }
    public int RoleId { get; set; }
}

    modelBuilder.Entity<UserRole>()
        .HasRequired(x => x.Role)
        .WithRequiredPrincipal()
        .HasForeignKey(x => x.RoleId);

    modelBuilder.Entity<UserRole>()
        .HasRequired(x => x.User)
        .WithRequiredPrincipal()
        .HasForeignKey(x => x.UserId);

    modelBuilder.Entity<UserRole>().HasKey(x => new { x.UserId, x.RoleId });

您发布的确切情况可能会通过多对多关系实现:

    modelBuilder.Entity<User>()
        .HasMany(x => x.Roles)
        .WithMany()
        .Map(m => 
        { 
            m.ToTable("UserRole"); 
            m.MapLeftKey("UserId"); 
            m.MapRightKey("RoleId"); 
        });

使用此方法,您将获得UserRole表,其中主键在UserId和RoleId上定义。