我正在按照本教程使用EF Core 1.1实现我的友谊系统:http://www.codedodle.com/2014/12/social-network-friends-database.html
Friendship.cs
public class Friendship
{
public Guid ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public Guid FriendId { get; set; }
public ApplicationUser Friend { get; set; }
public StatusCode Status { get; set; }
public Guid ActionUserId { get; set; }
public ApplicationUser ActionUser { get; set; }
public byte[] Timestamp { get; set; }
}
public enum StatusCode
{
Pending = 0,
Accepted = 1,
Declined = 2,
Blocked = 3
}
ApplicationUser.cs
public class ApplicationUser : IdentityUser<Guid>
{
...
public ICollection<Friendship> FriendRequestsMade { get; set; }
public ICollection<Friendship> FriendRequestsAccepted { get; set; }
public byte[] Timestamp { get; set; }
}
MyDbContext.cs
public class SocialCircleContext : IdentityDbContext<ApplicationUser, Role, Guid>
{
builder.Entity<Friendship>()
.HasIndex(x => new { x.ApplicationUserId, x.FriendId })
.IsUnique();
builder.Entity<Friendship>()
.HasOne(x => x.ApplicationUser)
.WithMany(y => y.FriendRequestsMade)
.HasForeignKey(x => x.ApplicationUserId).OnDelete(DeleteBehavior.Restrict);
builder.Entity<Friendship>()
.HasOne(x => x.Friend)
.WithMany(y => y.FriendRequestsAccepted)
.HasForeignKey(x => x.FriendId);
}
添加迁移初始迁移的结果
无法确定“ApplicationUser”类型的导航属性“Friendship.ActionUser”所代表的关系。手动配置关系,或从模型中忽略此属性。
此外,随着EF Core的快速发展,我发现了许多不同的方法。我不确定我的自我引用多对多关系的实现,有人可以给我一些建议吗?
谢谢! :)
答案 0 :(得分:1)
理想情况下,一旦关系发现中的歧义得到解决,EF应按惯例创建其余的关系,但由于错误而不会发生。 (提起Bug)
您的模型类对于您要执行的操作是正确的。为了使EF成功构建模型,需要填写的缺失部分很少。
首先,让我们解决你看到的异常。
您的ApplicationUser
类有2个指向Friendship
的集合导航。 Friendship
类有3个引用导航,指向ApplicationUser
。虽然EF Core在按惯例创建关系方面做得很好,但在这种情况下,它不知道如何创建导航 - 反向导航对。因此,需要通过注释/流畅的API来输入用户。在您的情况下,您使用流畅的API创建2个关系,每侧使用2个导航。这使我们只有导航Friendship.ActionUser
没有任何关系。在这一点上,EF Core对如何创建关系没有任何困惑,但由于它没有这样做的错误。这意味着您必须使用流畅的API手动配置此关系。
builder.Entity<Friendship>().HasOne(e => e.ActionUser).WithOne().HasForeignKey<Friendship>(e => e.ActionUserId);
这将创建一对一的关系。您可以使用HasOne(...).WithMany()
创建一对多关系。
这会让你超越上述错误。现在您将看到另一个错误,因为类Friendship
没有定义主键。虽然文章说创建一个唯一索引,但对于多对多连接表,连接表配置了复合PK,以便它可以表示唯一的连接。因此,您应该使用以下代码,而不是像上面那样调用HasIndex
。
builder.Entity<Friendship>().HasKey(e => new { e.ApplicationUserId, e.FriendId });
在上面的代码之后,您可以删除HasIndex
调用,因为PK始终是唯一的,并且大多数数据库都为PK定义了索引。
通过以上更改,您的模型应该可以正常工作。
其他事情:由于Friendship.ActionUser
定义的关系有点模棱两可,因为它是一对一或一对多,或许根本不应该是一种关系。 ActionUserId应采用ApplicationUserId
或FriendId
之一,您可以通过选择其中一个导航轻松访问ActionUser。您可以在EF中制作ActionUser [NotMapped]
,并根据ApplicationUser/Friend
计算返回值ActionUserId
。虽然这些是设计选择。没有正确或错误的方式。