我正在构建的应用程序允许用户上传.csv文件,该文件最终将填充Ids匹配的现有SQL表的字段。首先,我使用LinqToCsv和foreach循环将.csv导入临时表。然后我有另一个foreach循环,我试图将临时表中的行循环到Ids匹配的现有表中。
控制器完成此过程的操作:
[HttpPost]
public ActionResult UploadValidationTable(HttpPostedFileBase csvFile)
{
var inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
var cc = new CsvContext();
var filePath = uploadFile(csvFile.InputStream);
var model = cc.Read<Credit>(filePath, inputFileDescription);
try
{
var entity = new TestEntities();
var tc = new TemporaryCsvUpload();
foreach (var item in model)
{
tc.Id = item.Id;
tc.CreditInvoiceAmount = item.CreditInvoiceAmount;
tc.CreditInvoiceDate = item.CreditInvoiceDate;
tc.CreditInvoiceNumber = item.CreditInvoiceNumber;
tc.CreditDeniedDate = item.CreditDeniedDate;
tc.CreditDeniedReasonId = item.CreditDeniedReasonId;
tc.CreditDeniedNotes = item.CreditDeniedNotes;
entity.TemporaryCsvUploads.Add(tc);
}
var idMatches = entity.Authorizations.ToList().Where(x => x.Id == tc.Id);
foreach (var number in idMatches)
{
number.CreditInvoiceDate = tc.CreditInvoiceDate;
number.CreditInvoiceNumber = tc.CreditInvoiceNumber;
number.CreditInvoiceAmount = tc.CreditInvoiceAmount;
number.CreditDeniedDate = tc.CreditDeniedDate;
number.CreditDeniedReasonId = tc.CreditDeniedReasonId;
number.CreditDeniedNotes = tc.CreditDeniedNotes;
}
entity.SaveChanges();
entity.Database.ExecuteSqlCommand("TRUNCATE TABLE TemporaryCsvUpload");
TempData["Success"] = "Updated Successfully";
}
catch (LINQtoCSVException)
{
TempData["Error"] = "Upload Error: Ensure you have the correct header fields and that the file is of .csv format.";
}
return View("Upload");
}
上面代码中的问题是tc
在第一个循环中,但匹配是在循环后用var idMatches = entity.Authorizations.ToList().Where(x => x.Id == tc.Id);
定义的,所以我只得到第一个循环的最后一项。
所以我需要在第一个循环中放置var idMatches = entity.Authorizations.ToList().Where(x => x.Id == tc.Id);
,但是在第二个循环中我无法访问它。如果我嵌套第二个循环,那么它是缓慢的方式。有什么办法可以将上面的语句放在第一个循环中并仍然可以访问它。或者任何其他想法来完成同样的事情?谢谢!
答案 0 :(得分:2)
不要使用多个循环,而是随时跟踪已处理的ID,然后排除任何重复项。
[HttpPost]
public ActionResult UploadValidationTable(HttpPostedFileBase csvFile)
{
var inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
var cc = new CsvContext();
var filePath = uploadFile(csvFile.InputStream);
var model = cc.Read<Credit>(filePath, inputFileDescription);
try
{
var entity = new TestEntities();
var tcIdFound = new HashSet<string>();
foreach (var item in model)
{
if (tcIdFound.Contains(item.Id))
{
continue;
}
var tc = new TemporaryCsvUpload();
tc.Id = item.Id;
tc.CreditInvoiceAmount = item.CreditInvoiceAmount;
tc.CreditInvoiceDate = item.CreditInvoiceDate;
tc.CreditInvoiceNumber = item.CreditInvoiceNumber;
tc.CreditDeniedDate = item.CreditDeniedDate;
tc.CreditDeniedReasonId = item.CreditDeniedReasonId;
tc.CreditDeniedNotes = item.CreditDeniedNotes;
entity.TemporaryCsvUploads.Add(tc);
}
entity.SaveChanges();
entity.Database.ExecuteSqlCommand("TRUNCATE TABLE TemporaryCsvUpload");
TempData["Success"] = "Updated Successfully";
}
catch (LINQtoCSVException)
{
TempData["Error"] = "Upload Error: Ensure you have the correct header fields and that the file is of .csv format.";
}
return View("Upload");
}
如果要确保获取任何重复ID的最后一个值,请将每个TemporaryCsvUpload
记录存储在字典中,而不是仅使用HashSet
。同样基本的想法。
答案 1 :(得分:0)
在第一个循环之前声明idMatches
,但不要实例化它或将其值设置为null
。然后你就可以在两个循环中使用它了。在第一个循环之前移动声明之后,您仍将使用简单的Where
获得上次迭代的值。您需要将现有列表与当前迭代的结果连接起来。