我来自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中完成。错误消息肯定表明它不可行。有人可以证实吗?
答案 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上定义。