查询树结构

时间:2015-08-06 16:36:33

标签: c# sql-server entity-framework

我正在使用EntityFramework,但如果需要可以使用其他方式

情况就是这样:我有一个SQL Server数据库,其方案类似于:

A           B           C           AhasB         AhasC
________    ________    ________    __________    ___________
AId         BId         CId         AId           AId
...         Btxt        Ctxt        BId           CId
            BParent     ...
            ...

其中...表示对问题不重要的其他列。

CAhasC用于在冗长的进程中保存数据,并在进程完成时清除,因此我始终以空的方式开始 现在,该流程从在线资源中获取了大量数据(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.CTxtB.Btxt中与AhasB连接的??相同}}

此外(此处输入B.Btxt)我还希望它与B的任何父级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必须连接A和C BBTxt相关CTxt等于CTxt或者谁的父母(或祖父母等)的BTxt与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 相同。

希望我的解释不会过于复杂化:p

EDIT1:根据@ dotctor的评论,这是我真正的谢玛的形象(不是我认为它会增加很多问题)

My Real Schema

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);
}

这是我现在正在做这项工作的真实代码:

RelativeLayout

此代码可以完成这项工作,但是对于ConcursosPublicos的1000多名成员和Contatos的7000多名成员(未来将继续增长的contatos),可能需要15到20个小时才能完成。由于这是一个日常过程,我需要一种更有效的方式来填写ConcursosContatos

1 个答案:

答案 0 :(得分:0)

您需要一些递归来获取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表。