C# 绕过实体框架导入/更新大量数据

C# 绕过实体框架导入/更新大量数据,c#,.net,entity-framework,C#,.net,Entity Framework,我有一个基于实体框架的完全工作的生产站点,现在我需要每周将大量数据导入数据库。 数据以文本文件的形式出现,我逐行检查数据库,查看它是否存在,是否更新了任何已更改的内容,如果没有,则插入。 我遇到的问题是,运行完整的导入过程大约需要32个小时,一些文件必须手动拆分成更小的块,以避免实体框架似乎造成的内存问题。我已经设法降低了内存的增长速度,但上次我运行一个文件而不拆分它时,它运行了大约12个小时,然后以超过1.5gb的速度耗尽了内存。 有人能给我建议导入这些数据的最佳方法吗?我听说过sqlbulk

我有一个基于实体框架的完全工作的生产站点,现在我需要每周将大量数据导入数据库。 数据以文本文件的形式出现,我逐行检查数据库,查看它是否存在,是否更新了任何已更改的内容,如果没有,则插入。 我遇到的问题是,运行完整的导入过程大约需要32个小时,一些文件必须手动拆分成更小的块,以避免实体框架似乎造成的内存问题。我已经设法降低了内存的增长速度,但上次我运行一个文件而不拆分它时,它运行了大约12个小时,然后以超过1.5gb的速度耗尽了内存。
有人能给我建议导入这些数据的最佳方法吗?我听说过sqlbulkcopy,但不确定它是否正确使用。有人能举些例子吗?或者提出更合适的建议。例如,我是否应该使用标准的.net sql命令创建实体的副本,并可能使用存储过程?不幸的是,在这种情况下,您需要远离实体框架;开箱即用EF只进行逐行插入。您可以做一些有趣的事情,例如,或者完全忽略EF,使用ADO.Net SqlBulkCopy手动编写将执行大容量插入的类


编辑:如果性能可以接受,也可以使用当前方法,但需要定期重新创建上下文,而不是对所有记录使用相同的上下文。我怀疑这就是内存消耗惊人的原因。

尽管SqlBulkCopy在托管代码中非常方便,但我认为最快的方法是使用纯sql进行操作-鉴于SqlBulkCopy不容易进行升级,您无论如何都需要执行下面的合并部分

假设您的文本文件为csv格式,并且在SQL Server上以C:\Data\TheFile.txt的形式存在,并且行尾标准化为CR-LF\r\n

假设数据是ID,Value1,Value2

此SQL命令将在暂存表中插入具有ID、Value、Value2列且数据类型兼容的FILE_暂存,然后更新实际表格FILE_表格注意:下面的代码未测试

  truncate table TheFile_Staging
    BULK INSERT TheFile_Staging FROM'C:\Data\TheFile.txt'
 WITH (fieldterminator=',', rowTerminator='\r\n',FirstRow=2)
  //FirstRow=2 means skip Row#1 - use this when 1st row is a header.

MERGE TheFile_Table as target
USING (SELECT ID,Value1,Value2 from TheFile_Staging) as source
on target.ID = source.ID
WHEN MATCHED THEN
  UPDATE SET target.Value1=source.Value1, target.Value2=source.target2
WHEN NOT MATCHED THEN 
  INSERT (id,Value1,Value2) VALUES (source.Id,source.Value1,source.Value2);
您可以创建一个存储过程,并将其设置为运行或从代码调用,等等。这种方法的唯一问题是错误处理批量插入有点混乱-但只要数据输入正常,那么速度就相当快

通常我会在WHERE子句中添加某种验证检查,使用合并的select只获取数据方面有效的行


可能还值得指出的是,暂存表的定义应该省略任何非null、主键和标识约束,以便可以无错误地读入数据,特别是在源数据中到处都有空字段的情况下;我通常也更喜欢将日期/时间数据作为普通nvarchar拉入—这样可以避免格式错误的日期导致导入错误,并且您的MERGE语句可以根据需要执行强制转换或转换,同时忽略和/或记录到错误表中遇到的任何无效数据。

我建议您使用BCP导入然后使用原始SQL合并/更新数据。这不是你应该考虑用EF做的事情,所以逐行分析文本文件。然后使用EF逐行更新或插入?Bulkcopy仅用于插入,因此需要了解更多有关该过程的信息。无法对bulkcopy的插入进行批处理,但潜在的问题是,如果某个记录在尚未处理的插入批中,该记录将不知道它是更新。有多少行?需要多长时间?以下是一些简单的步骤来提高EF批量插入/更新的性能:代码逐行读取文件,这是一个以制表符分隔的txt文件,然后每行将该行转换为实体对象,然后在该对象中使用来自该文件的id在数据库中查找该对象。如果存在,则检查不同之处;如果不存在,则更新,则在数据库中创建新实体。如果有人能提供一个使用存储过程或SQL语句的SQL批量复制或标准SQL.net方法的示例,我将不胜感激。我尝试过这个方法,但a无法使它与我的文件一起工作。这是一个样本。。。客户Id客户名称客户地址客户归属客户出生日期1 Jordan Reyes Toribio 100 a测试地址FE 1962-02-09 00:00:00@TomHawkin,很遗憾听到它不适合你;您能否提供尝试时遇到的错误的一些详细信息?当前错误为“批量加载数据转换错误类型不匹配或第1行第4列CustomerGender的指定代码页的字符无效”。该字段是一个nvarchar10@TomHawkin-是否有些数据包含
此字段为空,但表def上的约束为非空?我应该提到,暂存表定义通常应该删除大多数约束-请参阅更新的回答我意识到了这个问题。该文件有一个标题行。有没有办法总是跳过第一行?