2013-07-12 3 views
0

Я пытаюсь заставить GroupJoin работать с несколькими неизвестными ключами с помощью LINQ.LINQ Composite Key GroupJoin с ключами, неизвестными во время компиляции

Я видел решения с анонимными типами, но ключи всегда были заранее определены. В моем случае они определены пользователем, поэтому я не буду знать эту информацию во время компиляции. Я попытался использовать список ключевых значений и массив ключевых значений, но они никогда не совпадают.

Так ... это работает как шарм:

Func<Component, string> getKeyValue = x => x.Attributes       //from attributes 
              .Single(a => a.Name == _keyAttribute) //selects the key attribute 
              .Value;        //gets attribute value 

var leftJoin = source.GroupJoin(target,     //join 
           getKeyValue,   //on the same 
           getKeyValue,   //condition 
           (src, corresp) => new 
           { 
            src, 
            corresp 
           }) 
        .SelectMany(z => z.corresp.DefaultIfEmpty() 
               .Select(tgt => new { z.src, tgt })) //selects matching 
        .ToList();             //source and target 

, но это не делает:

Func<Component, List<string>> getKeyValues = x => x.Attributes     //from attributes 
           .Where(a => _keyAttributes.Contains(a.Name)) //selects key attributes 
           .OrderBy(a => a.Name)      //order them by name 
           .Select(a => a.Value)      //gets attributes' values 
           .ToList(); 
var leftJoin = source.GroupJoin(target,     //join 
           getKeyValues,   //on the same 
           getKeyValues,   //condition 
           (src, corresp) => new 
           { 
            src, 
            corresp 
           }) 
        .SelectMany(z => z.corresp.DefaultIfEmpty() 
               .Select(tgt => new { z.src, tgt })) //selects matching 
        .ToList();             //source and target 

Если это помогает, это структура, я работаю над:

List<string> _keyAttributes; 
List<Component> source; 
List<Component> target; 

[DataContract] 
public class Component 
{ 
    [DataMember] 
    public List<Attribute> Attributes { get; set; } 

    public Component() 
    { 
     new List<Attribute>(); 
    } 
} 

[DataContract] 
public class Attribute 
{ 
    [DataMember] 
    public string Name { get; set;} 
    [DataMember] 
    public string Value { get; set;} 
} 

Есть ли способ решить эту проблему с помощью библиотеки LINQ или мне нужен мой собственный метод расширения GroupJoin?

ответ

0

Проблема в том, что селектор getKeyValues, который вы предоставите, будет возвращать List с каждого Component для сравнения. Возвращенный List от каждого будет сравниваться с помощью ссылки, поэтому в основном у вас это происходит:

var listA = new List<string> { "SomeString" }; 
var listB = new List<string> { "SomeString" }; 

bool areListsEqual = listA == listB; 

areListsEqual вернет ложь, так как они сравниваются по ссылке. По существу, вам понадобится либо другой EqualityComparer (доступный для добавления через перегруз GroupJoin), либо вам нужен способ сравнения свойств по значение.

пример чего-то, что будет работать (но не обязательно хороший способ сделать это) будет:

Func<Component, string> getKeyValues = x => 
    string.Join(",", x.Attributes 
         .Where(a => _keyAttributes.Contains(a.Name)) 
         .OrderBy(a => a.Name) 
         .Select(a => a.Value).ToArray()); 

Это создаст строку, представляющую значения в каждом списке, и которые будут использоваться для сравнения. Лучшим способом было бы использовать EqualityComparer, который имеет свою собственную логику для того, что делает списки фактически равными на основе значений, содержащихся внутри. См. here, как вы можете сравнить два списка.

+0

Не думал о соединении значений. Так как они все струны, это работает. Я согласен с вами в том, что это не обязательно хороший способ сделать это, но я думаю, что это сработает. Не с запятой, а с уникальной комбинацией символов. Спасибо! –

+0

Думая лучше, я останусь с решением реализации EqualityComparer для списка или T [] и передав его в качестве дополнительного аргумента GroupJoin. –

+0

IEqualityComparer - это путь! Спасибо! –

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