2015-08-06 3 views
0

Я работаю с EntityFramework, но можно использовать и другие способы, при необходимостизапроса Структура дерева

Вот так: у меня есть базы данных SQL Server с той же схемой:

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

Where ... средств другие столбцы не важны для проблемы.

Таблицы 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.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 и C, если A подключен к B, что либо имеет BTxt равным CTxt, или у которого есть родитель (или grand-parent и т. д.), есть BTxt, то же самое, что и CTxt.

Надежда я не усложнять мой объяснения здесь: р

EDIT1: согласно коментарии @ dotctor, вот это образ моей реальной Шма (не то, что я думаю, что это добавит много к вопросу)

My Real Schema

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 (с контатами на пути к росту в будущем) для завершения может потребоваться от 15 до 20 часов. Так как это ежедневный процесс, мне нужен более эффективный способ заполнить ConcursosContatos

+0

'AhasB' и' AhasC' генерируются инфраструктурой сущностей? Можете ли вы опубликовать код для своих POCOs? – dotctor

+0

Они были созданы с использованием EntityFramework Model-First - поэтому poco автоматически генерируется - есть ли что-то конкретное, что вы хотите увидеть? – 537mfb

+0

Итак, у вас есть объекты с именем 'AhasB' и' AhasC'? – dotctor

ответ

0

Вам нужна рекурсия, чтобы получить генеалогическое древо на вашей таблице B.В SQL Server вы можете сделать это с КТР:

;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.

+0

Привет @JeffO - я смотрел на С, и это выглядело многообещающим, но, где в вашем примере вы сравниваете BTxt с CTxt или нами A вообще? Кроме того, как использовать «с» при использовании сущностей? – 537mfb

+0

Один шаг за раз. Это результат, который вы ожидаете получить от всех дочерних родительских отношений в вашей таблице B? Если это так, вы можете использовать это как дополнительный запрос для присоединения к этим таблицам для сравнения. Я не знаю, как это сделать в Entity Framework, но вы можете обернуть это в пользовательскую функцию таблицы. – JeffO

+0

так, получив результат этой операции отдельно. Это то, что я делаю сейчас, но это делает его очень длинным процессом - 15-20 часов (см. Раздел «Редактировать в вопросе»). – 537mfb

Смежные вопросы