[英]Linq query for selecting an item from tree structure, but to look in the whole depth
[英]Query tree structure
我正在使用EntityFramework,但如果需要可以使用其他方式
就是这种情况:我有一个SQL Server数据库,其方案类似于:
A B C AhasB AhasC
________ ________ ________ __________ ___________
AId BId CId AId AId
... Btxt Ctxt BId CId
BParent ...
...
其中...
表示对问题不重要的其他列。
表C
和AhasC
会在一个漫长的过程中保留数据,并在过程完成时清除它们,因此我总是从两个空开始。现在,该过程从在线资源中获取大量数据(1000多个记录)并将其存储在C
。 填充C
后,我想基于以下内容填充表AhasC
:
INSERT INTO C (AId, CId) VALUES (
SELECT A.AId, C.CId
FROM A, B, C, AhasB
WHERE A.AId = AhasB.AId AND B.BId = AhasB.BId AND
C.CTxt IN (
SELECT D.BTxt
FROM B AS D
WHERE D.BId = B.BId OR ??
)
)
在我解释我需要什么之前??
让我浏览一下我在这里的内容:
我想在表AhasC中插入A.AId,C.CId对,以便在所有对中C.CTxt
都与在B.Btxt
中连接到A的AhasB
。
此外(在这里输入??
),我也希望它与B
的任何父代的B.Btxt
匹配。
例:
A B
_______ ____________________________________
AId = 1 BId = 1, BTxt = 'a', BParent = Null
AId = 2 BId = 2, BTxt = 'b', BParent = 1
AId = 3 Bid = 3, BTxt = 'c', BParent = 2
AId = 4 BId = 4, BTxt = 'x', BParent = Null
C AahsB
_____________________ _________
CId = 1, Ctxt = 'b' AId = 1, BId = 3
CId = 2, CTxt = 'z' AId = 3, BId = 4
这应导致:
AhasC
____________
AId = 1, CId = 1
如此反复, AhasC
必须连接A
,如果和C A
连接到B
,要么有BTxt
等于CTxt
,或者谁的父母(或盛大的父母等)具有BTxt是一样CTxt
。
希望我不会在这里给我过多的解释:p
编辑1:根据@dotctor的评论,这是我真正的shema的图像(不是我认为这会增加很多问题)
A = Contatos
B = Termos
C = ConcursosPublicos
AhasB = TermosContatos
AhasC = ConcursosContatos
A.AId = Contatos.Id
B.BId = Termos.Id
C.CId = ConcursosPublicos.Id
B.BTxt = Termos.Area
C.CTxt = ConcursosPublicos.Area
B.BParent = Termos.Pai
这是我目前正在执行此工作的真实代码:
public static void Connect(ProgressBar progress)
{
lock (Locker)
using (var ctx = new ConcursosContainer())
{
int i = 0;
IList<Contatos> contatos = ctx.Contatos.ToList();
progress.Invoke((MethodInvoker) (() =>
{
progress.Value = 0;
progress.Maximum = contatos.Count;
}));
foreach (Contatos contato in contatos)
{
Console.WriteLine(contato.Id);
List<Termos> tree = GetTree(ctx, contato.Id).SelectMany(x => x.ToArray()).ToList();
List<int> attr = ctx.ConcursosContatos.Where(x => x.ContatoId == contato.Id).Select(x => x.ConcursoId).ToList();
IList<ConcursosPublicos> concursosPublicos = ctx.ConcursosPublicos.Where(x => !attr.Contains(x.Id)).ToList();
foreach (ConcursosPublicos concursosPublico in concursosPublicos)
{
if (tree.Any(termo => (termo.Tipo == concursosPublico.TipoConc) && concursosPublico.Area.Trim().EndsWith(termo.Area)))
{
ctx.ConcursosContatos.Add(new ConcursosContatos
{
ContatoId = contato.Id,
ConcursoId = concursosPublico.Id
});
i++;
}
if (i == 9)
{
ctx.SaveChanges();
i = 0;
}
}
progress.Invoke((MethodInvoker) (progress.PerformStep));
}
if (i > 0)
ctx.SaveChanges();
}
}
private static IEnumerable<Stack<Termos>> GetTree(ConcursosContainer ctx, int id)
{
var res = new List<Stack<Termos>>();
IQueryable<Termos> terms = ctx.Termos.Where(x => ctx.TermosContatos.Any(y => (y.ContatoId == id) && (y.TermoId == x.Id)));
foreach (Termos term in terms)
{
var stack = new Stack<Termos>();
if (term.Pai.HasValue)
AddParent(ctx, stack, term);
stack.Push(term);
res.Add(stack);
}
return res;
}
private static void AddParent(ConcursosContainer ctx, Stack<Termos> stack, Termos term)
{
Termos pai = ctx.Termos.First(x => x.Id == term.Pai.Value);
if (pai.Pai.HasValue)
AddParent(ctx, stack, pai);
stack.Push(pai);
}
该代码可以完成工作,但是对于1000+的ConcursosPublicos成员和7000+的Contatos成员(将来还会有contatos成长),它可能需要15到20个小时才能完成。 由于这是日常工作,因此我需要一种更有效的方式来填写ConcursosContatos
您需要进行一些递归才能将族谱添加到B表中。 在SQL Server中,您可以使用CTE执行此操作:
;with chld as (
select B.BId, B.BTxt, B.BParent
from dbo.B as B
union all
select chld.BId , b1.BTxt, b1.BParent
from dbo.B as B1
inner join chld
on B1.BId = chld.BParent
)
select BId, BTxt from chld option(maxrecursion 32767)
结果集:
BId BTxt
1 a
2 b
3 c
4 x
3 b
3 a
2 a
如果这是不正确的,则无需进一步。 否则,您可以根据需要将其连接到其他表以填充AhasC表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.