2012-12-13 2 views
6

다른 유형의 목록이 있는데 여기에 참여하여 동적 결과를 얻으려고합니다.join을 사용하여 linq 결과의 모든 열을 얻는 방법

list1이 기본 목록이라고 가정 해 보겠습니다. 목록 2와 3은 추가 정보가있는 목록입니다. 언젠가 나는 정보를 원한다. 그리고 다른 실행에서 나는 그들 중 하나를 필요로하지 않는다.

추가 정보가 필요한 경우 얻을 수있는 열을 알고 있습니다. 목록 1과 2 모두에 정보를 가정

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

필요 : 목록 3에서

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

정보 때때로 (, 그것은 항상 결과에 추가됩니다 이제 진정한 포함)이 필요하다 :

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의 결과는 하나의 열에 결합됩니다. 나는 동적으로 모든 결과를 제공받을 수있는 방법

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

: 나는 수도 여부를 공동 수 (다른 유형도) 10 목록을 사용하기 때문에, 같은 것을 최종 결과를 알 수 있으므로 확인하는 것은 매우 어렵다 바람직하게는 모든 조인 된 목록에 대해 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

쉬운 방법은 없습니다. 에스.

어쨌든 dynamic으로 전송 중이므로 ExpandoObject을 일부 도우미 메서드와 함께 사용할 수 있습니다.

다음과 같은 헬퍼 필요합니다

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

그리고보다 간단하게 모든 쿼리에 ToList에 호출하기 전에 .Select(GetFlatExpando)를 사용

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 클래스에 넣어) :

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

서 :

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

이처럼 사용 ;-) – user369122

+0

@ user369122 : 확인하십시오. –

+0

안녕하세요, 빠른 코딩 주셔서 감사합니다!디버그 모드에서 "동적 뷰"에서 결과 행당 올바른 결과를 볼 수 있지만이 출력을 DataGrid 뷰의 소스로 어떻게 사용할 수 있습니까? dataGridView1.DataSource = result에 아무 것도 표시되지 않습니다. – user369122

관련 문제