c# - FirstOrDefault() 在迭代中添加天数的时间

标签 c# entity-framework ado.net

这里遇到了一种边缘情况问题。我的任务是将所有数据从一个数据库提取到另一个数据库,其中目标数据库具有不同的架构。

我选择编写一个 WinForms 实用程序来在必要时使用 Entity Framework/ADO.NET 进行数据映射和传输。

到目前为止,除了这个拥有 250 万条记录的特定表之外,这一方法效果很好。当我忽略所有外键时,传输总共大约需要 10 分钟,但是当我开始使用 FirstOrDefault() 映射外键时,会调用内存中已移动到目标数据库的数据列表,相当长的时间实际上,需要的时间加上 4 天。

在接下来的几天里我需要经常运行这个工具,所以这对我来说是不能接受的。

这是我当前的方法(不是我的第一个方法,这是为了提高效率进行多次试验和错误的结果):

private OldModelContext _oldModelContext { get; } //instantiated in controller

using (var newModelContext = new NewModelContext())
    {
        //Takes no time at all to load these into memory, collections are small, 3 - 20 records each
        var alreadyMigratedTable1 = newModelContext.alreadyMigratedTable1.ToList();
        var alreadyMigratedTable2 = newModelContext.alreadyMigratedTable2.ToList();
        var alreadyMigratedTable3 = newModelContext.alreadyMigratedTable3.ToList();
        var alreadyMigratedTable4 = newModelContext.alreadyMigratedTable4.ToList();
        var alreadyMigratedTable5 = newModelContext.alreadyMigratedTable5.ToList();

        var oldDatasetInMemory = _oldModelContext.MasterData.AsNoTracking().ToList();//2.5 Million records, takes about 6 minutes 

        var table = new DataTable("MasterData");
        table.Columns.Add("Column1");
        table.Columns.Add("Column2");
        table.Columns.Add("Column3");
        table.Columns.Add("ForeignKeyColumn1");
        table.Columns.Add("ForeignKeyColumn2");
        table.Columns.Add("ForeignKeyColumn3");
        table.Columns.Add("ForeignKeyColumn4");
        table.Columns.Add("ForeignKeyColumn5");

        foreach(var masterData in oldDatasetInMemory){
            DataRow row = table.NewRow();

            //With just these properties mapped, this takes about 2 minutes for all 2.5 Million
            row["Column1"] = masterData.Property1;
            row["Column2"] = masterData.Property2;
            row["Column3"] = masterData.Property3;

            //With this mapping, we add about 4 days to the overall process.
            row["ForeignKeyColumn1"] = alreadyMigratedTable1.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
            row["ForeignKeyColumn2"] = alreadyMigratedTable2.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
            row["ForeignKeyColumn3"] = alreadyMigratedTable3.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
            row["ForeignKeyColumn4"] = alreadyMigratedTable4.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
            row["ForeignKeyColumn5"] = alreadyMigratedTable5.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);

            table.Rows.Add(row);
        }   

        //Save table with SQLBulkCopy is very fast, takes about a minute and a half.
    }
}

注意:uniquePropertyOn(New/Old)Dataset 通常是数据集之间共享的唯一描述字符串,无法匹配 ID,因为它们在数据库之间不相同。

我已经尝试过:

  1. 没有使用 foreach,而是使用 linq select 语句进行强制转换,但没有太大改进。
  2. 使用.Where(predicate).FirstOrDefault(),没有看到任何明显的改进
  3. 针对 iqueryable 而不是迁移数据列表运行 FirstOrDefault(),没有看到任何改进。
  4. 映射到列表而不是数据表,但这对映射速度没有影响,而且还会使批量保存速度变慢。

我一直在考虑将 foreach 转换为并行 foreach 循环并锁定对数据表的调用,但我一直遇到

Entity Framework connection closed issues

当使用并行 foreach 查询内存列表时......不太确定那是什么,但最初速度结果是有希望的。

如果有人认为这是正确的道路,我很乐意发布该代码/错误,但我不再确定了..

最佳答案

我尝试的第一件事是字典,并预取列:

var fk1 = oldDatasetInMemory.Columns["ForeignKeyColumn1"];

// ...

var alreadyMigratedTable1 = newModelContext.alreadyMigratedTable1.ToDictionary(
    x => x.uniquePropertyOnNewDataset);

// ...

if (alreadyMigratedTable1.TryGetValue(masterData.uniquePropertyOnOldDataset, out var val))
    row[fk1] = val;

但是,实际上:我也会尽量避免使用整个 DataTable 部分,除非它真的非常有必要。

关于c# - FirstOrDefault() 在迭代中添加天数的时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53647958/

相关文章:

c# - 将数据类型 varchar 转换为 bigint 时出错。内联 sql 语句

c# - 具有多个约束的通用方法

c# - 使用 MarshalByRefObject 进行奇怪的 .NET 远程处理 SerializationException

c# - SQLite 1.0.94 未出现在 EDM 提供程序上

asp.net - 如何在.net core框架中使用TransactionScope?我找不到它

c# - 动态数据 Web 应用程序给我错误?

c# - 使用 LdapConnection 连接到 OpenLDAP 时出错

c# - 多个实体到同一个 DbSet

c# - 英孚。在没有 [Required] 属性的情况下引发字符串字段的必需验证错误

c# - 是否可以扩展 DataColumn.Expression