Как я могу получить "уровни" самоссылающейся таблицы в LINQ? - PullRequest
1 голос
/ 20 июля 2011

Есть таблица Category с pk idCategory и внешним ключом с собственной ссылкой fiCategory.Это означает, что категории являются «основными категориями», когда fiCategory is null.Если fiCategory ссылается на другую категорию, это подкатегория.Но также верно, что эта подкатегория также имеет 1-n подкатегорий (с fiCategory связыванием с idCategory).

Q: Как я могу получить списокосновных категорий, подкатегорий, «подкатегорий», ... и т. д.с LINQ?

Backgound :

Я использую типизированные DataSets для сравнения данных с Server1 / MySQL с данными с Server2 / MS SQL-Server.После нормализации и очистки (есть несколько несоответствий) я хочу импортировать новые данные в SQL-сервер.Прежде всего я должен импортировать основные категории, затем подкатегории и так далее.В противном случае SQL-сервер выдаст исключение ограничения, когда я попытаюсь вставить строку с внешним ключом в категорию, которая еще не вставлена.

Это таблицы (слева MySQL-источник, справа SQL-Таблица назначения сервера):

Kategorie: MySQL-source Category: SQL-Server destination

Здесь я получаю новые строки в MySQL, которых нет в SQL-Server:

srcи dest набираются DataSets

Dim idSrc = From c In src.kategorie Select c.kategorie_id
Dim idDest = From c In dest.Category Select c.idCategory
Dim diff = idSrc.Except(idDest)
Dim needUpdate = diff.Any

Теперь я хочу импортировать новые строки.Таким образом, я получаю все «основные категории»:

Dim mainCat = From kat In src.kategorie
            Join d In diff
            On kat.kategorie_id Equals d
            Where kat.IsparentNull
        Select kat

For Each cat In mainCat
    Dim newCat = Me.dest.Category.NewCategoryRow
    newCat.idCategory = cat.kategorie_id
    newCat.Name = cat.name
    newCat.SetfiCategoryNull()
    dest.Category.AddCategoryRow(newCat)
    rowsUpdated += daCategoryOut.Update(dest.Category)
Next

Таким образом, я получаю все подкатегории:

Dim subCat = From kat In src.kategorie
               Join d In diff
               On kat.kategorie_id Equals d
               Where Not kat.IsparentNull
          Select kat

Оба LINQ-запроса работают, но какя получаю все "уровни" подкатегорий?Мне нужно вставить строки сверху вниз.Есть ли способ, который работает даже с любой глубиной?

По крайней мере, это не работает (повторяя pk-значения):

Dim subCatWithChild = From cat In subCat
                      Join child In 
                     (From kat In src.kategorie Where Not kat.IsparentNull)
                      On child.parent Equals cat.kategorie_id
                   Select cat

Я все еще изучаю LINQ и ценю любой видпредложения (также в C #).Заранее спасибо.

Примечание : Возможно, вы знаете способ, которым я могу временно отключить ограничение внешнего ключа в SQL-Server и включить его после того, как вставил все строки из ADO.NET.Это было бы намного проще.


Это решение благодаря @Tridus:

Dim mainCat = From kat In src.kategorie
          Where kat.IsparentNull
      Select kat

For Each kat In mainCat
   rowsUpdated += insertCategory(kat, diff, daCategoryOut)
Next

Это рекурсивная функция:

Private Function insertCategory(ByVal parent As CC_IN.kategorieRow, ByVal diff As IEnumerable(Of Int32), ByVal daCategoryOut As CC_OutTableAdapters.CategoryTableAdapter) As Int32
    Dim rowsInserted As Int32 = 0

    If diff.Contains(parent.kategorie_id) Then
        Dim newCat = Me.dest.Category.NewCategoryRow
        newCat.idCategory = parent.kategorie_id
        newCat.Name = parent.name
        If parent.IsparentNull Then
            newCat.fiCategory = parent.parent
        Else
            newCat.SetfiCategoryNull()
        End If
        dest.Category.AddCategoryRow(newCat)
        rowsInserted += daCategoryOut.Update(dest.Category)
    End If

    'get all childs from this parent
    Dim childs = From cat In Me.src.kategorie
               Where Not cat.IsparentNull AndAlso cat.parent = parent.kategorie_id
               Select cat
    'insert all childs for this parent
    For Each child In childs
        rowsInserted += insertCategory(child, diff, daCategoryOut)
    Next

    Return rowsInserted
End Function

1 Ответ

2 голосов
/ 20 июля 2011

Да, ограничения внешнего ключа можно временно отключить .

Лучший способ сделать это (кроме отключения внешних ключей и простого копирования строки за строкой):рекурсивно, начиная с основных категорий.Концептуально, вы бы сделали это:

Get the main categories (which you've done)
For each main category
   Is this one in the other DB? If not, add it.
   Get the sub-categories of this main category.
   For each sub-category
     Is this one in the other DB? If not, add it.
     Get the sub-categories of this sub-category.

и т. Д.Легко получить подкатегории той категории, которая у вас есть в настоящее время, поэтому, если вы просто начнете сверху, вы можете пройтись по всему дереву и добавить все, что отсутствует на другой стороне.

...