Объедините 3 списка с помощью LINQ

#c# #linq

Вопрос:

У меня проблема с объединением некоторых списков вместе, я думал, что это будет простое объединение LINQ, но я думаю, что это немного сложнее, и я хожу по кругу. У меня есть 3 таблицы ниже:

Таблица 1: Основной перечень продуктов

Продукт
ПРОД1
ПРОД2
ПРОД3
ПРОД4

Таблица 2: Продукт и соответствующая брошюра

Продукт Листовка
ПРОД1 Документ23
ПРОД2 Документ18
ПРОД3 Docu322
ПРОД4 Документ121

Таблица 3: Продукт и соответствующие этикетки

Продукт Этикетка
ПРОД1 Lbl29
ПРОД2 Lbl2
ПРОД3 Lbl222
ПРОД5 Lbl01

Конечный результат должен быть:-

Продукт Листовка Этикетка
ПРОД1 Документ23 Lbl29
ПРОД2 Документ18 Lbl2
ПРОД3 Docu322 Lbl222
ПРОД4 Документ121
ПРОД5 Lbl01

Примечание: Некоторые продукты могут не иметь брошюры, а некоторые продукты могут не иметь этикетки. Кроме того, листовки и этикетки могут быть связаны с несколькими продуктами.

Вот запрос, который я пытался выполнить, он сводит все воедино, но есть много странных дубликатов строк.

 PMatrix = (from a in AllProducts
           join b in Leaflets on a.Product equals b.Product into b_grp
           from b in b_grp.DefaultIfEmpty()
           join c in Labels on a.Product equals c.Product into c_grp
           from c in c_grp.DefaultIfEmpty()
           select new ProductMatrixModel
           {
               Product = a.Product,
               Leaflet = b == null ? "" : b.Leaflet, 
               Label = c == null ? "" : c.Label
           }).ToBindableCollection();
 

Извините за уродливые растянутые столы, я не вижу, как установить ширину.

Комментарии:

1. Да, извините, я это и имел в виду, я обновлю.

2. «У некоторых продуктов не может быть листовки, а у некоторых листовок не может быть этикетки», — но вы соединяете обе таблицы с продуктом без дополнительного условия для листовок с этикетками.

3. А, я вижу последние новости. Спасибо, теперь я понимаю.

4. Есть ли эти данные в базе данных/вам нужно, чтобы ответ был переведен в SQL формы A ЛЕВОЕ СОЕДИНЕНИЕ B ЛЕВОЕ СОЕДИНЕНИЕ C?

5. Возможно, также стоит отметить, что в вашем основном списке продуктов отсутствует опечатка Prod5?

Ответ №1:

Я не смог протестировать приведенный ниже код, но если вам нравятся выражения LINQ, вы можете попробовать что-то подобное. Некоторое время назад я сделал нечто подобное.

 AllProducts
.GroupJoin(Leaflets , l => l.Product, r => r.Product, (a, b) => new ProductMatrixModel { Product = a, Leaflet = b.FirstOrDefault() ?? string.Empty })
.GroupJoin(Labels, l => l.Product, r => r.Product, (a, b) => new ProductMatrixModel { Product = a.Product , Leaflet = a.Leaflet, Label = b.FirstOrDefault() ?? string.Empty })
.ToBindableCollection();
 

Приведенное выше выражение использует «FirstOrDefault», поэтому оно будет принимать первый результат из возможных совпадений соединений. Если вам требуются все совпадения соединения, то вам нужно обновить свое модальное свойство до списка и соответственно работать с данными.

Примером того, о чем я упоминал выше, может быть:

  1. Измените модальный на что-то вроде этого
     public class ProductMatrixModel
    {
       public ProductMatrixModel()
       {
          this.Labels = new List<string>();
          this.Leaflets = new List<string>();
       }
    
       public string Product { get; set; }
       public List<string> Labels { get; set; }
       public List<string> Leaflets { get; set; }
    }
     
  2. Затем используйте выражение LINQ следующим образом:
     AllProducts
    .GroupJoin(Leaflets , l => l.Product, r => r.Product, (a, b) => new ProductMatrixModel { Product = a, Leaflets = b })
    .GroupJoin(Labels, l => l.Product, r => r.Product, (a, b) => new ProductMatrixModel { Product = a.Product , Leaflets = a.Leaflets, Labels = b })
    .ToBindableCollection();
     

Приведенный выше запрос LINQ должен затем предоставить вам IEnumerable с каждым объектом Productmatrix Model, содержащим строку продукта, со связанным списком этикеток и листовок.

Вы можете зациклить каждый объект Productmatrix Model и делать с ним все, что вам нравится, связанные с ним данные. Я предполагаю, что вы хотели бы показать его в строке, разделенной запятыми.

Вот пример того, как отобразить список строк в виде строки, разделенной запятыми.

 string.Join(",", Leaflets.Select(s => s));
 

Комментарии:

1. Спасибо за ответ, но я получаю исключение со второй группой. Ошибка CS0411 Аргументы типа для метода ‘Перечислимы. Объединение групп<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter, TInner, TKey, TResult><TOuter>, IEnumerable<TOuter><TInner>, Функция<TInner><TOuter, TKey>, Функция<TOuter, TKey><TInner, TKey>, Функция<TInner, TKey><TOuter, IEnumerable<TInner>, TResult<TInner>>) не может быть выведено из использования. Попробуйте явно указать аргументы типа.

2. Что говорится в исключении?

3. А, понятно. Это связано с динамическими объектами. Я быстро обновлю информацию

4. Я обновил его, сделав его конкретным объектом для каждого соединения, а не динамическим, что должно решить проблему.

5. «Последовательность содержит больше, чем элемент» исключение для первой группы, присоединенной к новой модели ProductMatrixModel { … }