使用c#,Entity Framework

时间:2017-03-21 11:45:09

标签: c# sql database entity-framework linq

问题:我将请求发送到我的服务器,并将数组模型添加到数据库中。例如,One Array包含5000个模型。现在,如果表1中已经存在它们的引用ID,并且实际表中的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);
}

4 个答案:

答案 0 :(得分:1)

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

// 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

如果您使用字符串作为标识符,则应添加字符串比较器。如果您使用StringComparer.OrdinalIgnoreCase,它将确保不考虑案例,选择您需要的正确案例。

new HashSet<int>(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

答案 1 :(得分:0)

您可以过滤模型并添加此过滤器的结果。样本:

// 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:我不确定你的模型,但它应该像样本一样。

答案 2 :(得分:0)

我可以给你另一种方法来实现这个目标吗?

首先来看看这篇文章: Fastest Way of Inserting in Entity Framework

如您所见,实体框架不是进行大型工作的最佳方式。

因此,请考虑使用批量插入,然后执行存储过程来完成繁重的工作。

或者,如果你真的想通过C#&amp; EF,至少在分支中执行,即一次运行100个SaveChanges()。

干杯

答案 3 :(得分:0)

我会从表1中读取id,将表二读入两个Dictionary对象,如果键已经存在,则Dictionary是搜索速度最快的数据结构之一。您应该看到性能的巨大提升。然后,您可以将需要添加到表2中的ID添加到列表&lt;&gt;中并在最后进行批量插入。