2012-12-13 19 views
6

Katılmak ve dinamik bir sonuç almak istiyorum bazı farklı yazılan listeler var.Bir linq sonucundan tüm sütunları nasıl birleştirme ile birleştirme

Liste1'in temel liste olduğunu varsayalım. Liste 2 ve 3 ek bilgi içeren bir listedir. Bazen bilgi istiyorum ve diğer çalışmalarda onlara ihtiyacım yok.

Ek bilgilere ihtiyacım olursa, almak istediğim sütunları biliyorum. listede 1 ve 2 için hem bilgi varsayarak

public struct DateAndValue1 
{ 
    public uint DBDate { get; set; } 
    public double Value1 { get; set; } 
} 

public struct DateAndValue2 
{ 
    public uint DBDate { get; set; } 
    public double Value1 { get; set; } 
    public bool myBool { get; set; } 
    public int someInt { get; set; } 
} 

List<DateAndValue1> list1,list2; 
List<DateAndValue2> list3; 

bool addList2, addList3; 
list1 = new List<DateAndValue1>(); 
list1.Add(new DateAndValue1 { DBDate = 1, Value1 = 10 }); 
list1.Add(new DateAndValue1 { DBDate = 2, Value1 = 20 }); 
list1.Add(new DateAndValue1 { DBDate = 3, Value1 = 30 }); 
list1.Add(new DateAndValue1 { DBDate = 4, Value1 = 40 }); 
list1.Add(new DateAndValue1 { DBDate = 5, Value1 = 50 }); 
list1.Add(new DateAndValue1 { DBDate = 6, Value1 = 60 }); 

list2 = new List<DateAndValue1>(); 
list2.Add(new DateAndValue1 { DBDate = 1, Value1 = 100 }); 
list2.Add(new DateAndValue1 { DBDate = 1, Value1 = 200 }); 
list2.Add(new DateAndValue1 { DBDate = 3, Value1 = 300 }); 
list2.Add(new DateAndValue1 { DBDate = 4, Value1 = 400 }); 
list2.Add(new DateAndValue1 { DBDate = 5, Value1 = 500 }); 
list2.Add(new DateAndValue1 { DBDate = 5, Value1 = 600 }); 

list3 = new List<DateAndValue2>(); 
list3.Add(new DateAndValue2 { DBDate = 1, Value1 = 1000, myBool = true }); 
list3.Add(new DateAndValue2 { DBDate = 2, Value1 = 2000, myBool = true }); 
list3.Add(new DateAndValue2 { DBDate = 2, Value1 = 3000, myBool = true }); 
list3.Add(new DateAndValue2 { DBDate = 4, Value1 = 4000, myBool = true }); 
list3.Add(new DateAndValue2 { DBDate = 6, Value1 = 5000, myBool = true }); 
list3.Add(new DateAndValue2 { DBDate = 6, Value1 = 6000, myBool = true }); 

gereklidir: Listedeki 3'ten

List<dynamic> result = (from a in list1 
         join b in list2 
         on a.DBDate equals b.DBDate 
         select new { DBDate = a.DBDate, Result_A1 = a.Value1, Result_B1 = b.Value1 }).ToList<dynamic>(); 

bilgi bazen (her zaman sonuca eklenecektir şimdi gerçek ile) gereklidir:

if(true) 
{ 
    result = (from so_far in result 
       join c in list3 
       on so_far.a.DBDate equals c.DBDate 
       select new {so_far, Result_C1 = c.Value1,Result_C2=c.myBool }).ToList<dynamic>(); 
} 

Bu işe yarar, ancak a ve b'nin sonucu bir sütunda birleştirilir. Dinamik tüm sonuçlar mevcut alabilirsiniz nasıl

result = (from so_far in result 
     join c in list3 
     on so_far.a.DBDate equals c.DBDate 
     select new {DBDate= so_far.DBDate, Result_A1=so_far.Result_A1,Result_B1=so_far.Result_B1 , Result_C1 = c.Value1,Result_C2=c.myBool }).ToList<dynamic>(); 

: Olabilir veya olmasın ortak olmak (farklı türde de) yaklaşık 10 listemi yana, böyle bir şey sonuçta biliyoruz ve bu nedenle yapmak çok zor Farklı sütunlarda, tercihen birleştirilmiş tüm listeler için DBDDate atlanır, bu nedenle DBDate yalnızca bir sütundadır. Selamlar,

Matthijs

====================================== ======================

Ekstra bilgi (kod) Ben okunabilir bir sonuç almaya çalıştı:

public DataTable LINQToDataTable<T>(IEnumerable<T> varlist) 
    { 
      DataTable dtReturn = new DataTable(); 

      PropertyInfo[] columnNames = null; 

      if(varlist == null) 
       return dtReturn; 

      try 
      { 
       foreach(T rec in varlist) 
       { 
        if(columnNames == null) 
        { 
         columnNames = ((Type)rec.GetType()).GetProperties(); 
         foreach(PropertyInfo pi in columnNames) 
         { 
          Type colType = pi.PropertyType; 

          if((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>))) 
          { 
           colType = colType.GetGenericArguments()[0]; 
          } 

          dtReturn.Columns.Add(new DataColumn(pi.Name, colType)); 
         } 
        } 

        DataRow dr = dtReturn.NewRow(); 

        foreach(PropertyInfo pi in columnNames) 
        { 
         dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue 
         (rec, null); 
        } 

        dtReturn.Rows.Add(dr); 
       } 
      } 
      catch 
      { 
       return dtReturn; 
      } 
      return dtReturn; 
    } 

Ve bunu denedik :

 private class NestedPropertyInfo 
    { 
     public PropertyInfo Parent { get; set; } 
     public PropertyInfo Child { get; set; } 
     public string Name { get { return Parent.Name + "_" + Child.Name; } } 
    } 

    public DataTable LINQMultipleSelectToDataTable<T>(IEnumerable<T> varlist) 
    { 
     DataTable dtReturn = new DataTable(); 
     NestedPropertyInfo[] columns = null; 

     if(varlist == null) 
      return dtReturn; 

     foreach(T rec in varlist) 
     { 
      if(columns == null) 
      { 
       columns = (
        from p1 in rec.GetType().GetProperties() 
        from p2 in p1.PropertyType.GetProperties() 
        select new NestedPropertyInfo { Parent = p1, Child = p2 } 
        ).ToArray(); 

       foreach(var column in columns) 
       { 
        var colType = column.Child.PropertyType; 

        if((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>))) 
        { 
         colType = colType.GetGenericArguments()[0]; 
        } 

        dtReturn.Columns.Add(new DataColumn(column.Name, colType)); 
       } 
      } 

      DataRow dr = dtReturn.NewRow(); 

      foreach(var column in columns) 
      { 
       var parentValue = column.Parent.GetValue(rec, null); 
       var childValue = parentValue == null ? null : column.Child.GetValue(parentValue, null); 
       dr[column.Name] = childValue ?? DBNull.Value; 
      } 

      dtReturn.Rows.Add(dr); 
     } 

     return dtReturn; 
    } 

cevap

2

Bunu yapmak için kolay bir yol yoktur. s.

Zaten dynamic'a yayınladığınız için, bazı yardımcı yöntemlerle birlikte ExpandoObject'u kullanabilirsiniz.

Aşağıdaki yardımcıları gerekir:

public dynamic GetFlatExpando(object o) 
{ 
    IDictionary<string, object> result = new ExpandoObject(); 

    foreach(var property in o.GetType().GetProperties()) 
    { 
     var value = property.GetValue(o, null); 
     var expando = value as ExpandoObject; 
     if(expando == null) 
      result[property.Name] = value; 
     else 
      expando.CopyInto(result); 
    } 

    return result; 
} 

public static class Extensions 
{ 
    public static void CopyInto(this IDictionary<string, object> source, 
           IDictionary<string, object> target) 
    { 
     foreach(var member in source) 
     { 
      target[member.Key] = member.Value; 
     } 
    } 
} 

Ve daha basitçe tüm sorgularda ToList çağrısı önce .Select(GetFlatExpando) kullanın:

List<dynamic> result = (from a in list1 
         join b in list2 
         on a.DBDate equals b.DBDate 
         select new { DBDate = a.DBDate, Result_A1 = a.Value1, 
            Result_B1 = b.Value1 }) 
         .Select(GetFlatExpando) 
         .ToList<dynamic>(); 

if(true) 
{ 
    result = (from so_far in result 
       join c in list3 
       on so_far.DBDate equals c.DBDate 
       select new {so_far, Result_C1 = c.Value1,Result_C2=c.myBool }) 
       .Select(GetFlatExpando) 
       .ToList<dynamic>(); 
} 

Bu kod güzel yan etkiye DBDate olduğunu vardır sadece bir kez var.

veri kafes yapısı bağlama yapmak için, başka bir uzantı yöntemi gerekir (yukarıdaki Extensions sınıf koymak):

var dataTable = result.Cast<IDictionary<string, object>>() 
         .ToDataTable(); 
+0

ayakta:

public static DataTable ToDataTable(this IEnumerable<IDictionary<string, object>> source) { var result = new DataTable(); foreach(var rowData in source) { var row = result.NewRow(); if(result.Columns.Count == 0) { foreach(var columnData in rowData) { var column = new DataColumn(columnData.Key, columnData.Value.GetType()) result.Columns.Add(column); } } foreach(var columnData in rowData) row[columnData.Key] = columnData.Value; result.Rows.Add(row); } return result; } 

bu gibi kullanın ;-) – user369122

+0

@ user369122: Lütfen kontrol edin. –

+0

Merhaba, hızlı kodlama için teşekkürler!Hata ayıklama modunda "dinamik görünümde" sonuç satırında doğru sonuçları görebiliyorum, ancak bu çıkışı datagridview için nasıl kaynak olarak kullanabilirim. dataGridView1.DataSource = sonuç hiçbir şey göstermiyor. – user369122

İlgili konular