因此,我正在使用 EF6 执行一些原始 SQL 查询,并且我希望在事务中使用它,因为我正在根据查询的结果移动文件。这是代码的简短版本:
using (var dbTransaction = customDb.Database.BeginTransaction()) {
//Drop previously created tmp tables...
customDb.Database.ExecuteSqlCommand("IF OBJECT_ID('dbo.bbldkmember_tmp', 'U') IS NOT NULL DROP TABLE dbo.bbldkmember_tmp");
//Create a tmp table to keep all the bulk inserted records
customDb.Database.ExecuteSqlCommand("CREATE TABLE bbldkmember_tmp ( " + TableCreateGuts + " )");
//Insert all record from the files into the TMP table, move the files to the archive when done, error if the file fails.
foreach (var fileName in filenamesToHandle) {
try {
customDb.Database.ExecuteSqlCommand(
@"BULK INSERT bbldkmember_tmp FROM
'" + fileName + @"'
WITH (
FIELDTERMINATOR = ';',
ROWTERMINATOR = '\n',
CODEPAGE = 'ACP',
FIRSTROW = 2
);");
//Move file
File.Move(fileName, fileName.Insert(fileName.LastIndexOf(@"\"), @"\Archive"));
} catch (Exception err){
//return "Failed in file " + fileName;
//ignore but log error
retval += "Failed to load file " + fileName + " with error " + err.Message + "<br />";
File.Move(fileName, fileName.Insert(fileName.LastIndexOf(@"\"), @"\Error"));
}
}
//Start doing stuff with the records that we succeeded reading.
//Add a column that we can format a GUID into
customDb.Database.ExecuteSqlCommand(@"ALTER TABLE bbldkmember_tmp ADD col47 VARCHAR(255)");
//commit or rollback based on the results of a lot of checks
}
问题是在循环之后,EF对事务做了回滚。如果其中一个批量插入失败,则 ALTER TABLE 将失败,因为该列已经在表中。
我想做的是读取所有文件,忽略其中有错误的文件,然后处理内容并在此处出现故障时进行回滚。这可能吗?
编辑:这是来自 SQL Server Profiler 的屏幕截图,显示了正在发生的事情,显然有一些我不明白的地方......
编辑 #3:因此,我检查了文件中没有错误时会发生什么。如您所见,在批量插入之后没有启动第二个事务。
为了进一步尝试并制定解决方法,我尝试使用 SQL 服务器 TRY CATCH,使用 SqlQuery<>。结果是一样的:
//Insert all record from the files into the TMP table, move the files to the archive when done, error if the file fails.
foreach (var fileName in filenamesToHandle)
{
try
{
var c = customDb.Database.SqlQuery<int>(
@"--Bulk insert:
SET NOCOUNT ON;
BEGIN TRY
BULK INSERT bbldkmember_tmp FROM
'" + fileName + @"'
WITH (
FIELDTERMINATOR = ';',
ROWTERMINATOR = '\n',
CODEPAGE = 'ACP',
FIRSTROW = 2
);
SELECT 1
END TRY
BEGIN CATCH
SELECT 0
END CATCH
").ToList();
//Move file
retval += "Loaded file " + fileName + " with message " + (c.First() == 1 ?"ok":"fail") + "<br />";
if(File.Exists(fileName.Insert(fileName.LastIndexOf(@"\"), c.First() == 1 ? @"\Archive": @"\Error")))
File.Delete(fileName.Insert(fileName.LastIndexOf(@"\"), c.First() == 1 ? @"\Archive" : @"\Error"));
File.Move(fileName, fileName.Insert(fileName.LastIndexOf(@"\"), c.First() == 1 ? @"\Archive": @"\Error"));
}
catch (Exception err)
{
//Critical error
return "Failed to load file " + fileName + " with error " + err.Message + "<br />";
}
}
最佳答案
SQL Server 已中止事务。英孚没有参与。您可以尝试使用 TRY...CATCH
。我不确定这是否会阻止交易中止。 (您链接到此处不适用的问题,因为它是关于 XACT_ABORT
的)。
一个潜在的解决方案是在主事务之外进行批量插入。
关于c# - 停止 SQL Server/EF 执行自动回滚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29645799/