C# 如何使用LINQ with EF Core在树状层次结构中查找第一个父级
我有两个实体:C# 如何使用LINQ with EF Core在树状层次结构中查找第一个父级,c#,linq,tree,ef-core-2.1,C#,Linq,Tree,Ef Core 2.1,我有两个实体: 公共类子类 { [关键] 公共字符串Id{get;set;} 公共列表父项{get;set;} } 公共类父类 { [关键] 公共字符串Id{get;set;}//如果父项在子项中,则该Id为,否则为随机Guid。 公共字符串ParentId{get;set;}//此父级的父级Id。 公共字符串ChildId{get;set;}//child类中子类的Id。 公共子项{get;set;} } Db上下文的设置如下所示: 公共类MyContext:DbContext { 公共My
公共类子类
{
[关键]
公共字符串Id{get;set;}
公共列表父项{get;set;}
}
公共类父类
{
[关键]
公共字符串Id{get;set;}//如果父项在子项中,则该Id为,否则为随机Guid。
公共字符串ParentId{get;set;}//此父级的父级Id。
公共字符串ChildId{get;set;}//child类中子类的Id。
公共子项{get;set;}
}
Db上下文的设置如下所示:
公共类MyContext:DbContext
{
公共MyContext(DbContextOptions):基本(选项)
{
}
模型创建时受保护的覆盖无效(ModelBuilder)
{
builder.Entity();
builder.Entity().HasKey(k=>new{k.Id,k.ChildId});
builder.Entity()
.HasOne(h=>h.Child)
.有许多(w=>w.父母)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
}
}
实际数据是这样的,不是每个父项都在子项表中,而是每个子项都在子项表中。我想查询(从Child
表中)恰好是父子层次结构中最顶层的父对象的子对象。例如:
/*
* Tree:
* p1(P)--------p2 (P)------r2 (P&C)
* |-----------| |
* | c3 (P&C)
* | |
* | gc1 (C)
* r1 (P&C)---|
* | |
* c1 (C) c2 (C)
*/
此树应该为解决方案生成r1
和r2
,因为它们位于树的顶部以及子表中。换句话说,他们没有一个父母也是孩子
到目前为止,我的努力是:
使用(var ctx=new MyContext(选项))
{
var q=ctx.Set();
var mainQ=q.GroupJoin(q.Where(w=>w.Parents.Any()),
o=>o.Id,
i=>i.Parents.First().ParentId/*目前,我只想处理单亲。*/,,
(o,i)=>新的{o,i})
.Where(w=>!w.i.Any())
.选择(s=>s.o)
.Union(q.Where(w=>!w.Parents.Any());
}
但是,此查询给了我一个错误:
ArgumentException:输入序列必须具有Child类型的项,但具有Microsoft.EntityFrameworkCore.Query.Internal.AnonymousObject类型的项
非常感谢您的帮助。我刚刚设法弄明白:)
var childIds=ctx.Set().Select(s=>s.Id);
var query=ctx.Set()
.GroupJoin(ctx.Set(),o=>o.Id,i=>i.Id,(o,i)=>new{o,i})
.Where(w=>w.i.Any())
.选择(s=>s.o)
.包括(i=>i.父母)
.Where(w=>!w.Parents.Select(s=>s.Id).Intersect(childid.Any());
这个想法是找到所有作为父母的孩子(GroupJoin
后跟Where
子句),然后检查这些孩子的父母是否在children表中
如果有人有更好/更高性能的解决方案,请给出答案。为什么要求同时有父类和子类?一个节点
类难道还不够吗?有公共节点父节点
和公共节点子节点
?@Stucky由于超出此问题范围的原因,无法执行此操作。我需要单独存储它们。所以这些类不能以任何方式更改吗?@Stucky不,对不起:D
var childIds = ctx.Set<Child>().Select(s => s.Id);
var query = ctx.Set<Child>()
.GroupJoin(ctx.Set<Parent>(), o => o.Id, i => i.Id, (o, i) => new {o, i})
.Where(w => w.i.Any())
.Select(s => s.o)
.Include(i => i.Parents)
.Where(w => !w.Parents.Select(s => s.Id).Intersect(childIds).Any());