[英]Self referencing table Unique and distinct key pair with Ef Core Fluent API
我有一个多对多的自引用表,我希望有一个由两个外键组成的索引(或键)。 我还想避免相同的键重复和重新排序的键,比如
UserParentId xxx UserChildId
0 1 => 好的
0 2 => 好的
1 1 => 不行
2 0 => 不行,因为这个链接已经存在(见第二行)
最重要的是,我想使用无序提供的两个键在此索引中进行搜索。 就像是
_dbContext.UserToUsers.Find(userId1, userId2)
不知道 userId1 代表UserParentId还是UserChildId 。
我读过这个解决方案,它可能是一个很好的通用方法:
model 应该让UserparentId始终严格低于UserChildId ,控制器应该都知道这一点。
尽管如此,我仍然想知道是否已经在 EF CORE 中实现了类似的功能。 Index() 或 HasAlternateKey() 似乎没有提供我想要的。 任何的想法?
我的代码:
Model:
public class User
{
public int Id { get; set; }
public virtual ICollection<UserToUser> ChildrenUsers { get; set; }
public virtual ICollection<UserToUser> ParentUsers { get; set; }
}
public class UserToUser
{
public int Id { get; set; }
public int UserParentId { get; set; }
public int UserChildId { get; set; }
public virtual User ChildUser { get; set; }
public virtual User ParentUser { get; set; }
}
然后是我的 Fluent API 代码:
modelBuilder.Entity<UserToUser>().HasOne(d => d.ChildUser)
.WithMany(p => p.ParentUsers)
.HasForeignKey(d => d.UserParentId);
modelBuilder.Entity<UserToUser>().HasOne(d => d.ParentUser)
.WithMany(p => p.ChildrenUsers)
.HasForeignKey(d => d.UserChildId);
modelBuilder.Entity<UserToUser>()
.HasAlternateKey(x => new {x.UserChildId, x.UserParentId});
关于使用查找:
DbSet 上的 Find 方法使用主键值来尝试查找上下文跟踪的实体。 如果在上下文中找不到该实体,则将向数据库发送查询以在其中查找该实体。 如果在上下文或数据库中找不到该实体,则返回 Null。
Find
不支持通过替代键进行缓存查找,尽管尚未实现,但在未来将不再需要,因为查询缓存的替代方法将会发展,这意味着您可以编写一个名为Find
的扩展方法来专门执行您的要求。 看看这个问题和与之相关的问题: DbSet.Find by alternate key or predicate (你不是第一个提出这种请求的人)
因此,您要求 EF 在表中提供多个PrimaryKeys ,但也强制执行一旦用户是另一个用户的孩子,他们就不能成为同一用户的父级,因此所有这些组合的值必须是唯一的:
解决这个问题的另一种方法是认识到对于指定的UserId
您可以在每个User
上使用 Find ,特别是如果您无论如何都想要两个用户(因为链接表中没有其他信息,并且两个用户对象都可以包含链接引用)
var user1 = _dbContext.Users.Find(userId1);
var user2 = _dbContext.Users.Find(userId2);
var link = user1.ChildrenUsers.FirstOrDefault(x => x.UserChildId == userId2)
?? user2.ChildrenUsers.FirstOrDefault(x => x.UserChildId == userId1)
if (link != null)
{
// process when the link exists
}
这将绕过本地缓存,但可以完成工作:
_dbContext.UserToUsers.Where(x => UserParentId == userId1 && UserChildId == userId2
|| UserParentId == userId2 && UserChildId == userId1);
如果您只是进行存在性检查,则将
Where
更改为Any
,这样在服务器上运行同样有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.