簡體   English   中英

將LINQ查詢結果放入DataTable

[英]Put LINQ query result to DataTable

我有這個查詢:

        var smallExchangeReport =  from ex in exchangeProgReport
                                   where !string.IsNullOrEmpty(ex.comment)
                                   group ex by new { ex.siteName } into g
                                   select new SummuryReportTraffic
                                   {
                                       siteName = g.Key.siteName,
                                       exchangeCounter = g.Where(x => x.Prog1ToProg2Check == 1).Count(),
                                       descriptions = (from t in g
                                                       group t by new { t.comment, t.siteName } into grp
                                                       select new Description
                                                       {
                                                           title = grp.Key.comment,
                                                           numbers = grp.Select(x => x.comment).Count()
                                                       })
                                   };

在某些時候,我使用foreach循環將其放入dataTable中:

             foreach (var item in smallExchangeReport)
            {
                dr = smrTable.NewRow();

                foreach (var d in item.descriptions)
                {
                    dr[d.title] = d.numbers;
                }

                smrTable.Rows.Add(dr);
            }

但是我需要在不使用foreach循環的情況下將LINQ結果放入dataTable中。 所以我根據此鏈接對上面的代碼做了一些更改:

        DataTable dt = new DataTable();
        DataRow dr = dt.NewRow();

        IEnumerable<DataRow> smallExchangeReport =  from ex in exchangeProgReport.AsEnumerable()
                                   where !string.IsNullOrEmpty(ex.comment)
                                   group ex by new { ex.siteName } into g
                                   select new 
                                   {
                                       siteName = g.Key.siteName,
                                       exchangeCounter = g.Where(x => x.Prog1ToProg2Check == 1).Count(),
                                       descriptions = (from t in g.AsEnumerable()
                                                       group t by new { t.comment, t.siteName } into grp
                                                       select new
                                                       {
                                                           title = grp.Key.comment,
                                                           numbers = grp.Select(x => x.comment).Count()
                                                       })
                                   };

    // Create a table from the query.
    DataTable boundTable = smallExchangeReport.CopyToDataTable<DataRow>();

但是在更改的LINQ查詢上我得到此錯誤:

 Cannot implicitly convert type:'System.Collections.Generic.IEnumerable<<anonymous type: string siteName, int exchangeCounter>>' to 
     'System.Collections.Generic.IEnumerable<System.Data.DataRow>'. An explicit conversion exists (are you missing a cast?)

我的問題是如何強制轉換查詢以使其正常工作?我試圖強制轉換為(DataRow)LINQ的結果,但沒有成功。

在LINQ查詢中,您嘗試獲取IEnumerable<DataRow>作為結果,但實際上您選擇的是匿名類型的新對象: select new { siteName = .... } 這不能工作,因為您的匿名類型不能轉換為DataRow

您需要做的是使用將填充DataRow的函數,如下所示:

DataRow PopulateDataRow(
    DataTable table, 
    string siteName, 
    int exchangeCounter, 
    IEnumerable<Description> descriptions
{
    var dr = table.NewRow();  

    // populate siteName and exchangeCounter
    // (not sure how your data row is structured, so I leave it to you)

    foreach (var d in descriptions)
    {
        dr[d.title] = d.numbers;
    }

    return dr;
}

然后在您的LINQ查詢中,如下使用它:

IEnumerable<DataRow> smallExchangeReport =  
    from ex in exchangeProgReport.AsEnumerable()
    where !string.IsNullOrEmpty(ex.comment)
    group ex by new { ex.siteName } into g
    select PopulateDataRow(
        smrTable,
        siteName: g.Key.siteName,
        exchangeCounter: g.Where(x => x.Prog1ToProg2Check == 1).Count(),
        descriptions: (from t in g.AsEnumerable()
            group t by new { t.comment, t.siteName } into grp
            select new Description {
                title = grp.Key.comment,
                numbers = grp.Select(x => x.comment).Count()
            }
        )
    );

此解決方案擺脫了一個foreach (在行上),而留下了另一個(在描述上)。

如果刪除第二個foreach很重要...我仍將其保留在PopulateDataRow 我看不到刪除它的優雅方法。 您可以從LINQ查詢中調用一個方法,該方法的讀取方式像確定性函數,但實際上會產生在數據行上設置列值的副作用,但我覺得不合適。

這可以幫助您。

定義表結構。

DataTable tbl = new DataTable();
tbl.Columns.Add("Id");
tbl.Columns.Add("Name");

並且我們需要從匿名類型創建數據行。

    Func<object, DataRow> createRow = (object data) =>
    {
        var row = tbl.NewRow();
        row.ItemArray = data.GetType().GetProperties().Select(a => a.GetValue(data)).ToArray();
        return row;
    };

用假查詢測試:

    var enumarate = Enumerable.Range(0, 10);
    var rows = from i in enumarate
               select createRow( new { Id = i, Name = Guid.NewGuid().ToString() });
    var dataTable  = rows.CopyToDataTable<DataRow>();

在此處輸入圖片說明

您可以使用以下方法:

    private DataTable ListToDataTable<T>(List<T> objs, string tableName) {
        var table = new DataTable(tableName);
        var lists = new List<List<object>>();
        // init columns
        var propertyInfos = new List<PropertyInfo>();
        foreach (var propertyInfo in typeof(T).GetProperties()) {
            propertyInfos.Add(propertyInfo);
            if(propertyInfo.PropertyType.IsEnum || propertyInfo.PropertyType.IsNullableEnum()) {
                table.Columns.Add(propertyInfo.Name, typeof(int));
            } else {
                table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
            }
            table.Columns[table.Columns.Count - 1].AllowDBNull = true;
        }
        // fill rows
        foreach(var obj in objs) {
            var list = new List<object>();
            foreach(var propertyInfo in propertyInfos) {
                object currentValue;
                if(propertyInfo.PropertyType.IsEnum || propertyInfo.PropertyType.IsNullableEnum()) {
                    var val = propertyInfo.GetValue(obj);
                    if(val == null) {
                        currentValue = DBNull.Value;
                    } else {
                        currentValue = (int)propertyInfo.GetValue(obj);
                    }
                } else {
                    var val = propertyInfo.GetValue(obj);
                    currentValue = val ?? DBNull.Value;
                }
                list.Add(currentValue);
            }
            lists.Add(list);
        }
        lists.ForEach(x => table.Rows.Add(x.ToArray()));
        return table;
    }

編輯:

使用此擴展方法:

    public static bool IsNullableEnum(this Type t) {
        var u = Nullable.GetUnderlyingType(t);
        return u != null && u.IsEnum;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM