C# 复制ado.net数据表列表的最快方法

C# 复制ado.net数据表列表的最快方法,c#,.net,ado.net,C#,.net,Ado.net,我有一个数据表列表,如 List<DataTable> a = new List<DataTable>(); List a=新列表(); 我想制作此列表的深度副本(即复制每个数据表)。我的代码目前看起来像 List<DataTable> aCopy = new List<DataTable>(); for(int i = 0; i < a.Rows.Count; i++) { aCopy.Add(a[i].Copy()); }

我有一个数据表列表,如

List<DataTable> a = new List<DataTable>();
List a=新列表();
我想制作此列表的深度副本(即复制每个数据表)。我的代码目前看起来像

List<DataTable> aCopy = new List<DataTable>();
for(int i = 0; i < a.Rows.Count; i++) {
    aCopy.Add(a[i].Copy());
}
List aCopy=new List();
for(int i=0;i
性能绝对糟糕,我想知道是否有一种已知的方法可以加速这种复制


编辑:不必担心我为什么要这样做或需要这样做,只要接受它是遗留代码库的一部分,我无法更改它

如果必须复制数据表,它本质上是一个N次操作。如果数据表非常大,并导致大量分配,则可以通过一次执行一个部分来加快操作,但基本上受工作集的限制

如果必须复制一个数据表,它本质上是一个N次操作。如果数据表非常大,并导致大量分配,则可以通过一次执行一个部分来加快操作,但基本上受工作集的限制

您可以尝试以下方法-它给了我性能提升,尽管您的里程数可能会有所不同!我已经根据您的示例对其进行了调整,以演示如何使用另一种机制复制datatable—克隆表,然后将数据流化。您可以轻松地将其放入扩展方法中

List<DataTable> aCopy = new List<DataTable>(); 
for(int i = 0; i < a.Rows.Count; i++) { 
   DataTable sourceTable = a[i];
   DataTable copyTable = sourceTable.Clone(); //Clones structure
   copyTable.Load(sourceTable.CreateDataReader());
} 
另外,如果我们看看DataTable.Copy使用ILSpy做了什么:

public DataTable Copy()
{
    IntPtr intPtr;
    Bid.ScopeEnter(out intPtr, "<ds.DataTable.Copy|API> %d#\n", this.ObjectID);
    DataTable result;
    try
    {
        DataTable dataTable = this.Clone();
        foreach (DataRow row in this.Rows)
        {
            this.CopyRow(dataTable, row);
        }
        result = dataTable;
    }
    finally
    {
        Bid.ScopeLeave(ref intPtr);
    }
    return result;
}

internal void CopyRow(DataTable table, DataRow row)
{
    int num = -1;
    int newRecord = -1;
    if (row == null)
    {
        return;
    }
    if (row.oldRecord != -1)
    {
        num = table.recordManager.ImportRecord(row.Table, row.oldRecord);
    }
    if (row.newRecord != -1)
    {
        if (row.newRecord != row.oldRecord)
        {
            newRecord = table.recordManager.ImportRecord(row.Table, row.newRecord);
        }
        else
        {
            newRecord = num;
        }
    }
    DataRow dataRow = table.AddRecords(num, newRecord);
    if (row.HasErrors)
    {
        dataRow.RowError = row.RowError;
        DataColumn[] columnsInError = row.GetColumnsInError();
        for (int i = 0; i < columnsInError.Length; i++)
        {
            DataColumn column = dataRow.Table.Columns[columnsInError[i].ColumnName];
            dataRow.SetColumnError(column, row.GetColumnError(columnsInError[i]));
        }
    }
}
公共数据表副本()
{
IntPtr IntPtr;
Bid.ScopeEnter(out intPtr,“%d\n”,this.ObjectID);
数据表结果;
尝试
{
DataTable=this.Clone();
foreach(此.Rows中的DataRow行)
{
this.CopyRow(数据表,行);
}
结果=数据表;
}
最后
{
投标范围(参考intPtr);
}
返回结果;
}
内部无效复制行(DataTable表、DataRow行)
{
int num=-1;
int newRecord=-1;
if(行==null)
{
返回;
}
如果(row.oldRecord!=-1)
{
num=table.recordManager.ImportRecord(row.table,row.oldRecord);
}
如果(row.newRecord!=-1)
{
if(row.newRecord!=row.oldRecord)
{
newRecord=table.recordManager.ImportRecord(row.table,row.newRecord);
}
其他的
{
newRecord=num;
}
}
DataRow DataRow=table.AddRecords(num,newRecord);
如果(第行,错误)
{
dataRow.RowError=row.RowError;
DataColumn[]columnsInError=行。GetColumnsInError();
对于(int i=0;i

手术需要很长时间并不奇怪;它不仅是一行一行的,而且还进行额外的验证。

您可以尝试以下方法-它给了我性能提升,尽管您的里程数可能会有所不同!我已经根据您的示例对其进行了调整,以演示如何使用另一种机制复制datatable—克隆表,然后将数据流化。您可以轻松地将其放入扩展方法中

List<DataTable> aCopy = new List<DataTable>(); 
for(int i = 0; i < a.Rows.Count; i++) { 
   DataTable sourceTable = a[i];
   DataTable copyTable = sourceTable.Clone(); //Clones structure
   copyTable.Load(sourceTable.CreateDataReader());
} 
另外,如果我们看看DataTable.Copy使用ILSpy做了什么:

public DataTable Copy()
{
    IntPtr intPtr;
    Bid.ScopeEnter(out intPtr, "<ds.DataTable.Copy|API> %d#\n", this.ObjectID);
    DataTable result;
    try
    {
        DataTable dataTable = this.Clone();
        foreach (DataRow row in this.Rows)
        {
            this.CopyRow(dataTable, row);
        }
        result = dataTable;
    }
    finally
    {
        Bid.ScopeLeave(ref intPtr);
    }
    return result;
}

internal void CopyRow(DataTable table, DataRow row)
{
    int num = -1;
    int newRecord = -1;
    if (row == null)
    {
        return;
    }
    if (row.oldRecord != -1)
    {
        num = table.recordManager.ImportRecord(row.Table, row.oldRecord);
    }
    if (row.newRecord != -1)
    {
        if (row.newRecord != row.oldRecord)
        {
            newRecord = table.recordManager.ImportRecord(row.Table, row.newRecord);
        }
        else
        {
            newRecord = num;
        }
    }
    DataRow dataRow = table.AddRecords(num, newRecord);
    if (row.HasErrors)
    {
        dataRow.RowError = row.RowError;
        DataColumn[] columnsInError = row.GetColumnsInError();
        for (int i = 0; i < columnsInError.Length; i++)
        {
            DataColumn column = dataRow.Table.Columns[columnsInError[i].ColumnName];
            dataRow.SetColumnError(column, row.GetColumnError(columnsInError[i]));
        }
    }
}
公共数据表副本()
{
IntPtr IntPtr;
Bid.ScopeEnter(out intPtr,“%d\n”,this.ObjectID);
数据表结果;
尝试
{
DataTable=this.Clone();
foreach(此.Rows中的DataRow行)
{
this.CopyRow(数据表,行);
}
结果=数据表;
}
最后
{
投标范围(参考intPtr);
}
返回结果;
}
内部无效复制行(DataTable表、DataRow行)
{
int num=-1;
int newRecord=-1;
if(行==null)
{
返回;
}
如果(row.oldRecord!=-1)
{
num=table.recordManager.ImportRecord(row.table,row.oldRecord);
}
如果(row.newRecord!=-1)
{
if(row.newRecord!=row.oldRecord)
{
newRecord=table.recordManager.ImportRecord(row.table,row.newRecord);
}
其他的
{
newRecord=num;
}
}
DataRow DataRow=table.AddRecords(num,newRecord);
如果(第行,错误)
{
dataRow.RowError=row.RowError;
DataColumn[]columnsInError=行。GetColumnsInError();
对于(int i=0;i

手术需要很长时间并不奇怪;它不仅是逐行的,而且还进行额外的验证。

您应该指定列表的容量,否则它将不得不在内部增长以容纳数据。有关详细说明,请参见

List<DataTable> aCopy = new List<DataTable>(a.Count);
List aCopy=新列表(a.Count);

您应该指定列表的容量,否则它将不得不在内部增长以容纳数据。有关详细说明,请参见

List<DataTable> aCopy = new List<DataTable>(a.Count);
List aCopy=新列表(a.Count);

如果您的搜索条件简单,我发现以下方法比LINQ等其他过滤记录的方法更有效:

    public static DataTable FilterByEntityID(this DataTable table, int EntityID)
    {
        table.DefaultView.RowFilter = "EntityId = " + EntityID.ToString();
        return table.DefaultView.ToTable();
    }

我发现以下方法比其他过滤记录的方法(如LINQ)更有效,只要您的搜索条件简单:

    public static DataTable FilterByEntityID(this DataTable table, int EntityID)
    {
        table.DefaultView.RowFilter = "EntityId = " + EntityID.ToString();
        return table.DefaultView.ToTable();
    }

数据表列表有多大?我不认为您可以在满足这些需求的同时加快它的速度。(也就是说,它是一个深度副本。)还要注意的是,在代码的发布版本中,性能会比在代码的调试版本中更好。DataTables列表有多大?我认为您不能在满足这些要求的同时加快它的速度。(也就是说,它是一个深度副本。)还要注意