2011-04-06 72 views
0

我有2个来自2个不同系统的相似数据的表示,我需要将一个系统中的每个实体与另一个系统中的实体进行匹配。VB.NET LINQ - 匹配分层数据到平面数据

体系是分层次的,表示为Dictionary(Of String, List(Of CategoryA))看起来像:

- "Organization 1" 
    - { Name = "Cat1", Id = 1} 
    - { Name = "Cat2", Id = 2} 
    - { Name = "Cat3", Id = 3} 

- "Organization 2" 
    - { Name = "Cat1", Id = 4} 
    - { Name = "Cat3", Id = 5} 
    - { Name = "Cat4", Id = 6} 

- "Organization 3" 
    - { Name = "Cat1", Id = 7} 
    - { Name = "Cat2", Id = 8} 
    - { Name = "Cat3", Id = 9} 
    - { Name = "Cat4", Id = 10} 

系统B是扁平的,表示为List(Of CategoryB)看起来有点像:

- { Org = "Organization 1", Name = "Cat1", Id = 100 } 
- { Org = "Organization 1", Name = "Cat2", Id = 101 } 
- { Org = "Organization 1", Name = "Cat3", Id = 102 } 

- { Org = "Organization 2", Name = "Cat1", Id = 103 } 
- { Org = "Organization 2", Name = "Cat2", Id = 104 } 
- { Org = "Organization 2", Name = "Cat4", Id = 105 } 

- { Org = "Organization 4", Name = "Cat1", Id = 106 } 
- { Org = "Organization 4", Name = "Cat2", Id = 107 } 
- { Org = "Organization 4", Name = "Cat3", Id = 108 } 
- { Org = "Organization 4", Name = "Cat4", Id = 109 } 

,基本上我需要什么do是将分层数据外部联接到组织名称(Dictionary.KeyCategoryB.Org)和类别名称(CategoryA.NameCategoryB.Name)上的展开数据留下我一个Dictionary(Of String, IEnumerable(Of Tuple(Of CategoryA, CategoryB)))或东西看起来是这样的:

- "Organization 1" 
    - { Name = "Cat1", Id = 1}, { Org = "Organization 1", Name = "Cat1", Id = 100 } 
    - { Name = "Cat2", Id = 2}, { Org = "Organization 1", Name = "Cat2", Id = 101 } 
    - { Name = "Cat3", Id = 3}, { Org = "Organization 1", Name = "Cat3", Id = 102 } 

- "Organization 2" 
    - { Name = "Cat1", Id = 4}, { Org = "Organization 2", Name = "Cat1", Id = 103 } 
    - { Name = "Cat3", Id = 5}, null 
    - { Name = "Cat4", Id = 6}, { Org = "Organization 2", Name = "Cat4", Id = 105 } 

- "Organization 3" 
    - { Name = "Cat1", Id = 7}, null 
    - { Name = "Cat2", Id = 8}, null 
    - { Name = "Cat3", Id = 9}, null 
    - { Name = "Cat4", Id = 10}, null 

我没有访问CategoryA目的是能够给组织属性适用于它,否则我会做它,使它更简单对我自己。我只是无法弄清楚如何加入Dictionary键和它的值中的一个项的属性,并最终得到任何有用的东西。我创建的最成功实施涉及For Each环路第一和LINQ查询中:

Given: 
    catA = Dictionary(Of String, List(Of CategoryA)) 
    catB = List(Of CategoryB) 

Dim result As New Dictionary(Of String, List(Of Tuple(Of CategoryA, CategoryB))) 

For Each kvp As KeyValuePair(Of String, List(Of CategoryA)) In catA 
    Dim orgName As String = kvp.Key 

    If Not result.ContainsKey(orgName) Then 
     result.Add(orgName, New List(Of Tuple(Of CategoryA, CategoryB))) 
    End If 

    Dim orgCategories As IEnumerable(Of CategoryB) = 
     From cat In catB Where cat.Org = orgName 

    Dim tmpResult As IEnumerable(Of Tuple(Of CategoryA, CategoryB)) = 
     From cat_a In kvp.Value 
     Group Join cat_b In orgCategories 
      On cat_a.Name Equals cat_b.Name 
     Into matchedCats = Group 
     From cat In matchedCats.DefaultIfEmpty 
     Select matches = Tuple.Create(cat_a, cat) 

    result(orgName).AddRange(tmpResult) 
Next 

它的工作好了,但我想它是在同一个语句。

回答

0

那么,这种有效的工作,但ID坚持你的循环!

Public Class CategoryA 
    Public Property Name As String 
    Public Property Id As Integer 
End Class 

Public Class CategoryB 
    Public Property Org As String 
    Public Property Name As String 
    Public Property Id As Integer 
End Class 

Private SystemA As New Dictionary(Of String, List(Of CategoryA)) 
Private SystemB As New List(Of CategoryB) 

Sub Main() 
    SystemA.Add("Org1", New List(Of CategoryA) From {New CategoryA() With {.Id = 1, .Name = "Cat1"}, 
                New CategoryA() With {.Id = 2, .Name = "Cat2"}, 
                New CategoryA() With {.Id = 3, .Name = "Cat3"}}) 
    SystemA.Add("Org2", New List(Of CategoryA) From {New CategoryA() With {.Id = 4, .Name = "Cat1"}, 
                New CategoryA() With {.Id = 5, .Name = "Cat2"}, 
                New CategoryA() With {.Id = 6, .Name = "Cat3"}}) 
    SystemA.Add("Org3", New List(Of CategoryA) From {New CategoryA() With {.Id = 7, .Name = "Cat1"}, 
                New CategoryA() With {.Id = 8, .Name = "Cat2"}, 
                New CategoryA() With {.Id = 9, .Name = "Cat3"}, 
                New CategoryA() With {.Id = 10, .Name = "Cat4"}}) 

    SystemB.Add(New CategoryB() With {.Org = "Org1", .Name = "Cat1", .Id = 100}) 
    SystemB.Add(New CategoryB() With {.Org = "Org1", .Name = "Cat2", .Id = 101}) 
    SystemB.Add(New CategoryB() With {.Org = "Org1", .Name = "Cat3", .Id = 102}) 
    SystemB.Add(New CategoryB() With {.Org = "Org2", .Name = "Cat1", .Id = 103}) 
    SystemB.Add(New CategoryB() With {.Org = "Org2", .Name = "Cat2", .Id = 104}) 
    SystemB.Add(New CategoryB() With {.Org = "Org2", .Name = "Cat4", .Id = 105}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat1", .Id = 106}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat2", .Id = 107}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat3", .Id = 108}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat4", .Id = 109}) 


    Dim AllOrgs = SystemA.Keys.Union(SystemB.Select(Function(b) b.Org).Distinct) 

    Dim BothCats2 = From org In AllOrgs 
        Let CatAList = If(Not SystemA.ContainsKey(org), New List(Of CategoryA), From cat In SystemA(org)) 
        Let CatBList = (From cat In SystemB Where cat.Org = org).ToList 
        Let AllCatNames = (From cat In CatAList Select cat.Name Distinct).Union(From cat In CatBList Select cat.Name Distinct) 
        Let BothCats = (From cat In AllCatNames 
            From A In CatAList.Where(Function(CatA) CatA.Name = cat).DefaultIfEmpty 
            From B In CatBList.Where(Function(CatB) CatB.Name = cat).DefaultIfEmpty) 
        Select org, BothCats 

End Sub