Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 关于大型循环中LINQ的使用_C#_Performance_Linq - Fatal编程技术网

C# 关于大型循环中LINQ的使用

C# 关于大型循环中LINQ的使用,c#,performance,linq,C#,Performance,Linq,我想知道在以下场景中推荐什么: 我有一个大循环,我遍历它以获得一个ID,然后将其存储在数据库中,如下所示: foreach (var rate in rates) { // get ID from rate name Guid Id = dbContext.DifferentEntity .Where(x => x.Name == rate.Name).FirstOrDefault(); // create new object with the

我想知道在以下场景中推荐什么:

我有一个大循环,我遍历它以获得一个ID,然后将其存储在数据库中,如下所示:

foreach (var rate in rates)
{
    // get ID from rate name
    Guid Id = dbContext.DifferentEntity
        .Where(x => x.Name == rate.Name).FirstOrDefault();

    // create new object with the newly discovered 
    // ID to insert into the database
    dbContext.YetAnotherEntity.Add(new YetAnotherEntity
    {
        Id = Guid.NewGuid(),
        DiffId = Id,
    }
}
这样做是否更好/更快(首先获取所有
differentity
id,而不是单独查询它们)

List differentity=dbContext.differentity;
foreach(利率中的var率)
{
//从费率名称获取ID
Guid Id=差异性
.Where(x=>x.Name==rate.Name).FirstOrDefault();
//使用新发现的对象创建新对象
//要插入到数据库中的ID
dbContext.YetAnotherEntity.Add(新的YetAnotherEntity
{
Id=Guid.NewGuid(),
DiffId=Id,
}
}

是不是可以忽略不计,或者这是我应该考虑的吗?谢谢你的建议。

你可以减少你在数据库中所做的查询的次数。例如,取所有的名字和查询发现的ID。 试试这样的

// get all names you have in rates list...
var rateNames = rates.Select(x => x.Name).ToList();

// query all Ids you need where contains on the namesList... 1 query, 1 column (Id, I imagine)
var Ids = dbContext.DifferentEntity.Where(x => rateNames.Contains(x.Name).Select(x => x.Id).ToList();

// loop in Ids result, and add one by one
foreach(var id in Ids)
    dbContext.YetAnotherEntity.Add(new YetAnotherEntity
    {
        Id = Guid.NewGuid(),
        DiffId = id,
    }

您可以减少在数据库中执行的查询数量。例如,使用名称包含的所有名称和查询findind ID

试试这样的

// get all names you have in rates list...
var rateNames = rates.Select(x => x.Name).ToList();

// query all Ids you need where contains on the namesList... 1 query, 1 column (Id, I imagine)
var Ids = dbContext.DifferentEntity.Where(x => rateNames.Contains(x.Name).Select(x => x.Id).ToList();

// loop in Ids result, and add one by one
foreach(var id in Ids)
    dbContext.YetAnotherEntity.Add(new YetAnotherEntity
    {
        Id = Guid.NewGuid(),
        DiffId = id,
    }

将您的费率名称存储在排序字符串数组(
string[]
)中,而不是存储在
列表或
集合中。然后使用
array.BinarySearch()
,以加快搜索速度。我将要编写的其余内容已由@Felipe在上面编写。

将您的费率名称存储在排序字符串数组中(
string[]
)而不是
列表
集合
。然后使用
Array.BinarySearch()
使您的搜索速度更快。我将要写的其他内容已经由上面的@Felipe编写。

让他们跑马!我们确实有很多不知道的地方。是否可以将所有实体都保存在内存中?它们中有多少是与
名称相关的重复项

一个简单的解决方案,只需从数据库获取一次数据,并使用并行性:

// Fetch entities
var entitiesDict = dbContext.DifferentEntity
     .Distinct(EqualityComparerForNameProperty).ToDictionary(e => e.Name); 

// Create the new ones real quick and divide into groups of 500 
// (cause that horse wins in my environment with complex entities, 
// maybe 5 000 or 50 000 fits your scenario better since they are not that complex?)
var newEnts = rates.AsParallel().Select((rate, index) => {
  new {
        Value = new YetAnotherEntity
           { Id = Guid.NewGuid(), DiffId = entitiesDict[rate.Name],},
        Index = index
     }
  })
.GroupAdjacent(anon => anon.Index / 500) // integer division, and note GroupAdjacent! (not GroupBy)
.Select(group => group.Select(anon => anon.Value)); // do the select so we get the ienumerables

// Now we have to add them to the database
Parallel.ForEach(groupedEnts, ents => {
   using (var db = new DBCONTEXT()) // your dbcontext
   {
     foreach(var ent in ents)       
       db.YetAnotherEntity.Add(ent);

     db.SaveChanges();
   }
});

一般来说,在数据库场景中,最昂贵的事情是获取和提交,因此请尽量将它们保持在最低限度。

让它们运行起来!我们确实不知道很多事情。是否可以将所有实体都保留在内存中?它们中有多少是与
名称相关的重复项

一个简单的解决方案,只需从数据库获取一次数据,并使用并行性:

// Fetch entities
var entitiesDict = dbContext.DifferentEntity
     .Distinct(EqualityComparerForNameProperty).ToDictionary(e => e.Name); 

// Create the new ones real quick and divide into groups of 500 
// (cause that horse wins in my environment with complex entities, 
// maybe 5 000 or 50 000 fits your scenario better since they are not that complex?)
var newEnts = rates.AsParallel().Select((rate, index) => {
  new {
        Value = new YetAnotherEntity
           { Id = Guid.NewGuid(), DiffId = entitiesDict[rate.Name],},
        Index = index
     }
  })
.GroupAdjacent(anon => anon.Index / 500) // integer division, and note GroupAdjacent! (not GroupBy)
.Select(group => group.Select(anon => anon.Value)); // do the select so we get the ienumerables

// Now we have to add them to the database
Parallel.ForEach(groupedEnts, ents => {
   using (var db = new DBCONTEXT()) // your dbcontext
   {
     foreach(var ent in ents)       
       db.YetAnotherEntity.Add(ent);

     db.SaveChanges();
   }
});

一般来说,在数据库场景中,最昂贵的是获取和提交,因此请尽量将它们保持在最低水平。

为什么您要问我们。尝试这两种方法,然后自己找出答案。我认为这两种代码是相同的。话虽如此,在任何应用程序中,执行DB查询通常是执行次数最少的操作之一。执行在一个非常大的循环中,每次迭代一次显然是一个非常非常糟糕的主意。实际上,您应该始终努力避免这样做。@KingKing他们当然不是。一个是在循环的每次迭代中执行DB查询;另一个是在循环的每次迭代中搜索内存中的列表。两者都不是,但仍然存在一个重要的问题两者之间的区别。@Servy我对LINQ to实体并没有真正的经验,但是如果延迟了
dbContext.differentity
,这两个代码应该是相同的。为什么你要问我们。试着两个,然后自己去发现。我认为这两个代码都是相同的。话虽如此,执行DB查询通常是性能最低的一个在任何应用程序中都会有单个操作。在一个非常大的循环的每次迭代中执行一个操作显然是一个非常非常糟糕的主意。实际上,您应该始终努力避免这样做。@KingKing他们当然不会这样做。一个是在循环的每次迭代中执行DB查询;另一个是在循环的每次迭代中搜索内存中的列表一个循环。两者都不是,但两者之间仍然有很大的区别。@Servy我在LINQ to entity方面没有真正的经验,但是如果推迟
dbContext.differentity
,这两个代码应该是相同的。Felipe的解决方案将导致数据库
in
子句,因此不会执行搜索数据库的设计使这种搜索非常高效,尤其是在相关列被索引的情况下。嗯……真的吗?他正在这样做。Select().ToList(),这应该将他的实体查询具体化为内存中的对象。速率已经是内存中的对象。据我们所知,它们从未来自数据库。如果您获取内存中的列表,并对ORM
中表达式lambda的参数使用
Contains
方法,它将(通常,取决于提供商)将其映射到caluse中的SQL,在该SQL中,列表中的项是IN中的所有值,lambda的参数是搜索的对象。Felipe的解决方案将导致数据库
IN
子句,因此不会在应用程序的内存中执行搜索。数据库旨在使此类搜索非常有效效率很高,尤其是相关列被索引的情况下。嗯……真的吗?他在做。Select().ToList(),这应该将他的实体查询具体化为内存中的对象。速率已经是内存中的对象。据我们所知,它们从未来自数据库。如果您获取内存中的列表,并对ORM
中表达式lambda的参数使用
Contains
方法,它将(通常,取决于提供商)将其映射到caluse中的SQL,其中列表中的项目是IN中的所有值,lambda的参数是被搜索的对象。他指出循环是一个大循环。由于
rates
很大,它不太可能执行此操作,因为
中的SQL
子句通常限于j只有几千件。假设他已经超过了,他需要把所有的东西都放进去