【发布时间】:2021-02-13 05:22:53
【问题描述】:
我需要将一个进程从 SQL Server 传输到我的应用程序代码。 T-SQL 进程使用 MERGE,如下所示,有条件地更新或插入。
-- Synchronize the InterestRates table with refreshed/new data from ImportRates_Stg table
MERGE InterestRates AS TARGET
USING ImportRates_Stg AS SOURCE
ON (TARGET.Effective = SOURCE.EffectiveDate)
-- When records are matched on the Effective date, update the records if there is any change to the Rate
WHEN MATCHED AND TARGET.Effective = SOURCE.EffectiveDate
THEN UPDATE SET TARGET.Rate = SOURCE.Rate
-- When no records are matched on the Effective date,
-- insert the incoming records from ImportRates_Stg table to InterestRates table
WHEN NOT MATCHED BY TARGET
THEN INSERT (Effective, Rate) VALUES (SOURCE.EffectiveDate, Rate);
我需要在 C# 中重现此功能,并且认为 LINQ 可能是实现此目的的最佳方式,但到目前为止,我的所有尝试都失败了。这是我到目前为止的代码。将数据从 excel 文件导入到列表中一切正常。当我到达实际逻辑来替换不起作用的 SQL MERGE 时......
public async Task<IActionResult> OnPostAsync()
{
// Perform an initial check to catch FileUpload class attribute violations.
if (!ModelState.IsValid)
{
return Page();
}
string filePath = RatesBatchImportFilepath + Path.GetFileName(Request.Form.Files["RatesExtract"].FileName);
using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
{
await Request.Form.Files["RatesExtract"].CopyToAsync(fileStream);
}
var newRates = new List<InterestRate>();
using (var wb = new XLWorkbook(filePath, XLEventTracking.Disabled))
{
var ws = wb.Worksheet(1);
DataTable dataTable = ws.RangeUsed().AsTable().AsNativeDataTable();
if (dataTable.Rows.Count > 0)
{
foreach (DataRow dataRow in dataTable.Rows)
{
if (dataRow.ItemArray.All(x => string.IsNullOrEmpty(x?.ToString()))) continue;
newRates.Add(new InterestRate()
{
Effective = Convert.ToDateTime(dataRow["PeriodEndingDate"]),
Rate = Convert.ToDecimal(dataRow["AY01NetPerf"])
});
};
}
}
IQueryable<InterestRate> existingRates = from s in _context.InterestRates
orderby s.Effective descending
select s;
foreach (var oldRate in existingRates)
{
DateTime ourDate = oldRate.Effective;
var thisUpdateQuery =
from thisRate in newRates
where thisRate.Effective == ourDate
select thisRate;
foreach (var rate in thisUpdateQuery)
{
oldRate.Effective = rate.Effective;
newRates.Remove(rate); // this causes an error.
}
}
foreach (var rate in newRates)
{
Rates.Add(rate);
}
_context.SaveChanges();
return RedirectToPage("./Index");
}
这是错误:InvalidOperationException:集合已修改;枚举操作可能无法执行。
【问题讨论】:
-
它抛出了什么错误?
-
我更新了问题以包含我遇到的错误。
-
EF 将不得不单独执行
INSERTs 和UPDATEs 来保存这些更改,更不用说您为获取数据而执行的查询以进行分析。MERGE将更有效率,因为它在集合上运行,而且它在语义上更加清晰,因为它简洁地描述了何时插入、何时更新以及为每个操作做什么。这段 C# 代码过多地处理了操作机制(现在从数据库服务器中离开)并且模糊了期望的结果。我建议使用原始 MERGE 语句进行原始 SQL 查询。 -
如果你
ToList()你的thisUpdateQuery会发生什么?foreach (var rate in thisUpdateQuery.ToList())
标签: c# sql-server visual-studio asp.net-core