优化用于将一个数据表转换为另一个数据表的代码

时间:2012-10-30 10:07:56

标签: c# linq-to-sql datatable

我们不得不将数据表转换为另一个数据表,其中主要是将源数据表转换为不同的格式。 按顺序思考它,我已经实现了如下:

DataTable riskTable;
this.InitializeRmmRiskTable(out riskTable); // Initializes the columns

var calculatedRisk = (from DataRow tradeRow in tradeTableToFilter.Rows
                  where tradeRow["TradeID"] != null
                  select new
                          {
                              ROW_ID = 0,
                              TCN = tradeRow["TradeID"].ToString(),                               
                              CCY = tradeRow["CURRENCY"],                                 
                              USD_VALUE = calculator.Invoke(tradeRow) // configured delegate that will fetch the value
                          }).Distinct();

foreach (var rowData in calculatedRisk)
{
    DataRow rowToAdd = riskTable.NewRow();

    rowToAdd["ROW_ID"] = rowData.ROW_ID;
    rowToAdd["TCN"] = rowData.TCN;
    rowToAdd["CCY"] = rowData.CCY;
    rowToAdd["USD_VALUE"] = rowData.USD_VALUE;

    riskTable.Rows.Add(rowToAdd);
}
return riskTable;

有关内存占用和执行周期方面的优化建议吗?

3 个答案:

答案 0 :(得分:2)

您可以轻松删除大量列查找:

object[] values = new object[4];
foreach (var rowData in calculatedRisk)
{
    values[0] = rowData.ROW_ID;
    values[1] = rowData.TCN;
    values[2] = rowData.CCY;
    values[3] = rowData.USD_VALUE;

    riskTable.Rows.Add(values);
}

这假设您知道列的顺序。否则,DataColumn API是最直接的,因此您可以存储4 DataColumn并在索引器中使用它们。这同样适用于读取代码,即

var tradeId = tradeTableToFilter.Columns["TradeID"];
var currency = tradeTableToFilter.Columns["CURRENCY"];

然后:

var calculatedRisk = (from DataRow tradeRow in tradeTableToFilter.Rows
    let tradeIdVal = tradeRow[tradeId]
    where tradeIdVal != null
    select new {
        ROW_ID = 0,
        TCN = tradeIdVal.ToString(),                               
        CCY = tradeRow[currency],                                 
        USD_VALUE = calculator.Invoke(tradeRow)
    }).Distinct();

使用Distinct意味着所有对象将再次缓存在内存中;如果你知道你需要这个,那很好,但在很多情况下这可能是多余的。

答案 1 :(得分:2)

一些提示而不改变代码mutch:

使用索引intead字符串id名称,而不是

rowToAdd["ROW_ID"] = rowData.ROW_ID;

我建议

rowToAdd[0] = rowData.ROW_ID;

另一个提示是,不是为每个元素创建对象DataRow rowToAdd,而是将对象的声明放在迭代之外。

此外,不使用foreach,而是使用for。

此外

var calculatedRisk = (from DataRow tradeRow in tradeTableToFilter.Rows
              where tradeRow["TradeID"] != null
              select
                  new
                      {
                          ROW_ID = 0,
                          TCN = tradeRow["TradeID"].ToString(),                               
                          CCY = tradeRow["CURRENCY"],                                 
                          USD_VALUE = calculator.Invoke(tradeRow) // configured delegate that will fetch the value
                      }).Distinct();

我会一直改变这句话,而不是将这种怪物用于一个对象的声明,我建议在婴儿步骤中进行,或者如果你可以直接访问数据,使用sql语句来过滤和获取数据。

我会使用确切的数据类型,而不是通用的var

更复杂的变化需要更多地了解代码...

答案 2 :(得分:1)

由于(评论)你提到你可以选择更改返回类型,我会声明如下:

public class TradeRisk {
    public int Id {get;set;}
    public string TCN {get;set;} // expand name to be meaningful
    public string Currency {get;set;}
    public decimal UsdValue {get;set;}
}

并将方法更改为返回List<TradeRisk>。我们可以应用与之前的答案相同的DataColumn技巧,但更改结果 - 注意保持结果相同,我们需要保留Distinct等。

var tradeId = tradeTableToFilter.Columns["TradeID"];
var currency = tradeTableToFilter.Columns["CURRENCY"];

var calculatedRisk = (from DataRow tradeRow in tradeTableToFilter.Rows
    let tradeIdVal = tradeRow[tradeId]
    where tradeIdVal != null
    select new {
        Id = 0,
        TCN = tradeIdVal.ToString(),                               
        Currency = tradeRow[currency],                                 
        UsdValue = calculator.Invoke(tradeRow)
    }).Distinct();

return (from row in calculatedRisk 
        select new TradeRisk {
            Id = row.Id, TCN = row.TCN,
            Currency = row.Currency,
            UsdValue = row.UsdValue
        }).ToList();

这可以避免所有DataTable开销。如果我们真的想要,我们也可以实现TradeRisk : IEquatable<TradeRisk>,然后执行:

return (
    from DataRow tradeRow in tradeTableToFilter.Rows
    let tradeIdVal = tradeRow[tradeId]
    where tradeIdVal != null
    select new TradeRisk {
        Id = 0,
        TCN = tradeIdVal.ToString(),                               
        Currency = tradeRow[currency],                                 
        UsdValue = calculator.Invoke(tradeRow)
    }).Distinct().ToList();