2012-12-13 72 views
6

我有一些不同類型的列表,我想加入並獲得動態結果。如何從linq結果加入所有列

比方說,list1是基礎列表。列表2和列表3是帶有額外信息的列表。有時我需要信息,而在其他運行中,我不需要(其中之一)。

如果我需要額外的信息,我知道我想獲得哪些列。

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 }); 

假設爲列表1和2都信息需要:

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>(); 

從列表3信息有時需要(現在爲真,它將總是被添加到結果):

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>(); 
} 

這是行得通的,但a和b的結果組合在一列中。由於我將使用約10名(也有不同的類型),可能是或不是合資,這是很難知道最終的結果,因此製造類似:

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>(); 

如何動態獲取所有的結果可用在不同的列中,最好跳過所有連接列表的DBDDate,所以DBDate只在一列中。 問候,

Matthijs

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

額外的信息(代碼)我試圖得到的結果可讀:

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; 
    } 

並試用了此一個:

 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; 
    } 

回答

2

有沒有簡單的方法來做到這一點秒。

因爲無論如何,你可以使用ExpandoObject以及一些輔助方法來使用dynamic

您將需要以下助手:

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; 
     } 
    } 
} 

而且比,只需在所有查詢使用.Select(GetFlatExpando)該呼叫之前ToList

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>(); 
} 

該代碼具有很好的副作用,即DBDate只存在一次。

要綁定到數據網格的工作,你需要另外擴展方法(把它放到Extensions類從上圖):

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; 
} 

使用方法如下:

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

站在;-) – user369122

+0

@ user369122:請檢查。 –

+0

嗨,感謝您的快速編碼!在調試模式下,我可以在「動態視圖」中查看每個結果行的正確結果,但是如何將此輸出用作datagridview的源。 dataGridView1.DataSource =結果不顯示任何內容。 – user369122