【问题标题】:How do I convert this looped code to a single LINQ implementation?如何将此循环代码转换为单个 LINQ 实现?
【发布时间】:2018-06-14 15:40:34
【问题描述】:

我正在尝试优化下面的代码,该代码逐个循环对象并进行数据库查找。我想编写一个 LINQ 语句,在一个事务中执行相同的任务。

这是我的低效循环代码;

IStoreUnitOfWork uow = StoreRepository.UnitOfWorkSource.GetUnitOfWorkFactory().CreateUnitOfWork(); 
var localRunners = new List<Runners>();
foreach(var remoteRunner in m.Runners) {                                                           
    var localRunner = uow.CacheMarketRunners.Where(x => x.SelectionId == remoteRunner.SelectionId && x.MarketId == m.MarketId).FirstOrDefault();  
    localRunners.Add(localRunner);
}

这是我在单个查询中执行相同操作的非常可行的尝试。好吧,这甚至不是一次尝试。我不知道从哪里开始。 remoteRunners 对象有一个复合键。

IStoreUnitOfWork uow = StoreRepository.UnitOfWorkSource.GetUnitOfWorkFactory().CreateUnitOfWork(); 
var localRunners = new List<Runners>();
var localRunners = uow.CacheMarketRunners.Where(x =>
   x.SelectionId in remoteRunners.SelectionId &&
   x.MarketId    in remoteRunners.MarketId);

感谢您的关注

【问题讨论】:

  • List localRunners = uow.CacheMarketRunners.Where(x => x.SelectionId == remoteRunner.SelectionId && x.MarketId == m.MarketId).Select(x => x.FirstOrDefault ()).ToList();
  • 你必须实际构建一个表达式,或者是那些条件一起像this
  • 另外,您可以创建两个值的字符串表示形式列表,例如 var remotes = m.Runners.Select(r =&gt; r.SelectionId + ";" + r.MarketId).ToList(),然后像 Where(x =&gt; remotes.Contains(x.SelectionId + ";" + x.MarketId)) 一样使用它。但是请注意,这不会像查询那样有效,因为它不能利用这些列上的任何索引。
  • @jdweng 这没有任何意义。
  • @juharr 谢谢。我想我可以让它这样工作。似乎不得不做一件痛苦的事情!我会试试看。

标签: c# linq


【解决方案1】:

所以你有一个对象m,它有一个属性MarketId。对象m 也有一个Runners 序列,其中每个Runner 都有一个属性SelectionId

您的数据库有CacheMarketRunners。每个CacheMarketRunner 都有一个MarketId 和一个SelectionId

您的查询应返回 allCacheMarketRunners,其中 MarketId 等于 m.MarketId 和包含在序列 m.Runners.SelectionId 中的 SelectionId

如果您的m 没有太多Runners,比如少于250,请考虑使用Queryable.Contains

var requestedSelectionIds = m.Runners.Select(runner => runner.SelectionId);
var result = CacheMarketRunners.Where(cacheMarketRunner =>
     cacheMarketRunner.MarketId == m.MarketId
     && requestedSelectionIds.Contains(cacheMarketRunner.SelectionId));

【讨论】:

  • 非常简洁的解释谢谢。就 Queryable.Contains 而言。我需要了解原因,stackoverflow.com/questions/39969964/… 解释了原因。
  • 这个答案有一个假设:m.Runner 中的每个项目只有一个匹配的CacheMarketRunner 与相等的SelectionId。原来,由于for循环,结果的数量必须等于m.Runner.Count(),但现在如果有多个CacheMarketRunnerm.Runner中的项目具有相同的SelectionId,则返回更多结果。
【解决方案2】:

为了提高性能,您需要缓存事务结果:

var marketRunners = uow.CacheMarketRunners.Where(x => x.MarketId == m.MarketId).ToList();

关于uow 的事务结果存储在List 中,这样您就不会在for 循环中进行事务处理。因此应该提高性能:

var localRunners = new List<Runners>();
foreach(var remoteRunner in m.Runners) {                                                           
    var localRunner = marketRunners.FirstOrDefault(x => x.SelectionId == remoteRunner.SelectionId);
    localRunners.Add(localRunner);
}

您甚至可以删除 for 循环:

var localRunners = m.Runners.Select(remoteRunner => marketRunners.FirstOrDefault(x => x.SelectionId == remoteRunner.SelectionId)).ToList();

【讨论】:

  • 这真的取决于数据库中的数据。第一个查询可能会返回比需要更多的数据。最好在 DB 端进行尽可能多的过滤。
猜你喜欢
  • 2010-10-09
  • 2023-01-22
  • 1970-01-01
  • 1970-01-01
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多