使用c#,实体框架改进查询的性能

使用c#,实体框架改进查询的性能,c#,sql,database,entity-framework,linq,C#,Sql,Database,Entity Framework,Linq,问题:我向服务器发送请求时,会将一组模型添加到数据库中。例如,一个阵列包含5000个模型。现在,所有这些都必须检查它们的引用Id是否已经存在于表1中,以及Id是否不在实际表中(在示例中命名为2)。如果是这样的话,我会把它添加到数据库中。我会问5000次,每个模型一次,这需要相当长的时间。因为我很少使用数据库和实体框架,所以我真的不知道如何改进查询。我做错了什么,我能改进什么 foreach(twoModel model in Models){ if (Context.TAB_One.All(

问题:我向服务器发送请求时,会将一组模型添加到数据库中。例如,一个阵列包含5000个模型。现在,所有这些都必须检查它们的引用Id是否已经存在于表1中,以及Id是否不在实际表中(在示例中命名为2)。如果是这样的话,我会把它添加到数据库中。我会问5000次,每个模型一次,这需要相当长的时间。因为我很少使用数据库和实体框架,所以我真的不知道如何改进查询。我做错了什么,我能改进什么

foreach(twoModel model in Models){
  if (Context.TAB_One.All(m => m.Id != model.RefId_One)) {
    continue;
  }
  if (Context.TAB_Two.Any(m => m.Id == model.Id)) {
    continue;
  }
Context.TAB_Two.Add(model);
}

您可以筛选模型并添加此筛选的结果。对于示例:

// define the array of IDs you want to search
var refIds = Models.Select(x => x.RefId_One).ToArray();
var ids = Models.Select(x => x.Id).ToArray();

// perform the queries to filter
var allModelOne = Context.TAB_One.All(m => !refIds.Contains(m.Id));
var anyModelTwo = Context.TAB_Two.Any(m => ids.Contains(m.Id));

// filter models 
var modelsToSave = model.Where(m => !allModelOne.Contains(m.Id) && !anyModelTwo.Contains(m.Id));

// save them
foreach(twoModel model in modelsToSave) {   
    Context.TAB_Two.Add(model);
}
在进行过滤之前,您的代码将避免对循环进行查询


Obs:我不确定您的型号,但它应该与样品类似。

我能给您另一种方法来实现这一点吗

首先看一下这篇文章:

正如您所看到的,实体框架并不是完成大型工作的最佳方式

考虑使用大容量插入,然后执行存储过程来执行硬工作。

或者,如果你真的想用C#&EF来实现,至少可以在分支中实现,即每次运行100次SaveChanges()


干杯

最简单的方法是返回数据库中的所有现有值并建立一个哈希列表

// I guessed that it is an int, change it accordingly
var tableOneLookup = new HashSet<int>(Context.TAB_One.Id.Select(x => x.Id));
var tableTwoLookup = new HashSet<int>(Context.TAB_Two.Id.Select(x => x.Id));

// example of checking (check based on code you had shown before)
var modelsNotInTabOne = Models.Where(model => !tableOneLookup.Contains(model.RefIdOne)).ToList();
var modelsNotInTabTwo = Models.Where(model => !tableOneLookup.Contains(model.Id)).ToList();

// now do something with the results like create entity instances
//我猜它是一个int,相应地修改它
var tableOneLookup=newhashset(Context.TAB_One.Id.Select(x=>x.Id));
var tableTwoLookup=newhashset(Context.TAB_Two.Id.Select(x=>x.Id));
//检查示例(根据之前显示的代码进行检查)
var modelsNotInTabOne=Models.Where(model=>!tableOneLookup.Contains(model.RefIdOne)).ToList();
var modelsNotInTabTwo=Models.Where(model=>!tableOneLookup.Contains(model.Id)).ToList();
//现在对结果执行一些操作,如创建实体实例
如果使用字符串作为标识符,则应添加字符串比较器。如果您使用StringComparer.OrdinalIgnoreCase,它将确保不考虑该案例,请选择您需要的正确案例

new HashSet<int>(Context.TAB_Two.Id.Select(x => x.Id), StringComparer.OrdinalIgnoreCase);
newhashset(Context.TAB_Two.Id.Select(x=>x.Id),StringComparer.OrdinalIgnoreCase);

选择2 如果您的表有大量记录,则上述解决方案不再有效。您可以通过查找数据库中的ID,然后根据该结果进行过滤来实现相反的目的

// create lists of just the ids
var modelOneIds = Models.Select(model => model.RefIdOne).ToList();
var modelTwoIds = Models.Select(model => model.Id).ToList();

// create a list of ids found in the db
var foundInTableOne = new List<int>();
var foundInTableTwo = new List<int>();

// iterate over the model in batches of 1000, the translated IN clause in Sql has a limit. You can tweak this number accordingly
const int batchSize = 1000;
for(int i = 0; i < Models.Count; i+=batchSize){
    var tmpModelOneIds = modelOneIds.Skip(i).Take(batchSize).ToList();
    var tmpModelTwoIds = modelTwoIds.Skip(i).Take(batchSize).ToList();

    foundInTableOne.AddRange(Context.TAB_One.Where(itm => tmpModelOneIds.Contains(itm.Id)).Select(itm => itm.Id));
    foundInTableTwo.AddRange(Context.TAB_Two.Where(itm => tmpModelTwoIds.Contains(itm.Id)).Select(itm => itm.Id));
}

// find the models not found in the DB
var modelsNotInTabOne = Models.Where(model => !foundInTableOne.Contains(model.RefIdOne)).ToList();
var modelsNotInTabTwo = Models.Where(model => !foundInTableTwo.Contains(model.Id)).ToList();

// now do something with the results like create entity instances
//仅创建ID列表
var modelOneIds=Models.Select(model=>model.RefIdOne.ToList();
var modelTwoIds=Models.Select(model=>model.Id).ToList();
//创建在数据库中找到的ID列表
var foundInTableOne=新列表();
var foundInTableTwo=新列表();
//Sql中的translated-in子句有一个限制。你可以相应地调整这个数字
常量int batchSize=1000;
对于(int i=0;itmpModelOneIds.Contains(itm.Id)).Select(itm=>itm.Id));
AddRange(Context.TAB_Two.Where(itm=>tmpModelTwoIds.Contains(itm.Id)).Select(itm=>itm.Id));
}
//查找数据库中未找到的模型
var modelsNotInTabOne=Models.Where(model=>!foundInTableOne.Contains(model.RefIdOne)).ToList();
var modelsNotInTabTwo=Models.Where(model=>!foundInTableTwo.Contains(model.Id)).ToList();
//现在对结果执行一些操作,如创建实体实例

我会将表1和表2中的id读入两个Dictionary对象,Dictionary是搜索键是否已经存在的最快数据结构之一。你应该看到性能有了很大的提高。然后,您可以将需要添加到表2中的id添加到列表中,并在末尾进行批量插入。

选项卡一和
选项卡二中分别找到的预期记录总数是多少?选项卡一将包含更少的记录。数据将存储在数据库中,永远不会/或只是很少被删除。因此,对于这两个选项卡,记录将随着时间的推移而增加。在我添加一组Tab_2数据的情况下,每个请求只添加一次Tab 1。你可以说有5000多倍的记录,但这可能不同于500条或未知记录(可能是20000条/一条记录)。简短的形式是:1…n,其中n可能在2000到6000之间。谢谢你的回答,正如你提到的,记录的数量正在迅速增加,因此它将成为一个巨大的数量。特别是在Tab_Two的情况下。@JSTW1212-很高兴它能为您工作。请考虑批改答案。