I need to transfer a process from SQL Server to my application code. The T-SQL process uses MERGE, as shown below, to conditionally update or insert.
-- 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);
I need to reproduce this functionality in C#, and am thinking that LINQ would likely be the best way to do this, but so far all of my attempts have failed. Here is the code that I have so far. Importing the data to a list from an excel file is all working. It is when I get to the actual logic to replace the SQL MERGE which is not working...
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");
}
Here is the Error: InvalidOperationException: Collection was modified; enumeration operation may not execute.