简体   繁体   English

实体框架将多个查询组合为一个

[英]Entity Framework combining multiple queries into one

I have a query which it need to run 300+ loops every single call. 我有一个查询,它需要在每个调用中运行300个以上的循环。 It takes about 10 seconds to complete a call even on a new database. 即使在新数据库上,也要花费大约10秒钟才能完成通话。 It's unacceptable for a WebAPI call. WebAPI调用是不可接受的。

var isAbnormal = false;
var list = new List<String>();

//Check date range, log them & return if there is any abnormal.
foreach (DateTime day in DateHelper.EachDay(startDate, endDate))
{
  var isActive = db.Operations.Any(x=>x.IsActive && x.Day == day);
  var object;
  var queryable = db.ObjectA.Where(x=>x.Day == day);

  if(isActive){
    queryable = db.ObjectA.First(x=>x.Day == day);

  LogUtil.Info($"{object.Name}");

  var isLogicACorrect = queryable.Any(x=>x.ObjectACount == 5);
  var isLogicBCorrect = queryable.Any(x=>x.ObjectBCount == 3);
  var isLogicCCorrect = queryable.Any(x=>x.ObjectCCount == 2);
  var isLogicDCorrect = queryable.Any(x=>x.ObjectDCount == 8);
  var isLogicECorrect = queryable.Any(x=>x.ObjectECount == 1);
  if(!isLogicACorrect){
    list.Add("Logic A is incorrect");
    isAbnormal = true;
    }

  //More logic codes & db calls here, which is just to select & validate.

}
return list;

How can I optimize the speed by combining all the queries into one? 如何通过将所有查询组合为一个来优化速度? The loop content literally the same except the day.There are total 15 queries to be call on each loop, 4500 db queries in a complete loop. 除了一天外,循环内容实际上是相同的。每个循环中总共要调用15个查询,一个完整循环中有4500个数据库查询。

Think in terms of sets and relational data and not procedurally. 根据集合和关系数据而不是程序来思考。 It's not easy to determine exactly what you want from your code (which contradicts itself - queryable is set by a call to db.ObjectA.Where(...) which is an IQueryable<ObjectA> but then it is also set by a call to db.ObjectA.First(...) , which is an ObjectA ; I'll assume you want the IQueryable<ObjectA> since later code references queryable.Any(...) ) but here's my guess: 从代码中准确地确定您想要的是不容易的(这与自身矛盾- queryable是通过对db.ObjectA.Where(...)的调用来设置的,它是一个IQueryable<ObjectA>但随后它也会通过调用来设置到db.ObjectA.First(...) ,这是一个ObjectA ;我假设您要使用IQueryable<ObjectA>因为以后的代码引用了queryable.Any(...) ),但这是我的猜测:

var days = DateHelper.EachDay( startDate, endDate );

var activeDaysIsLogicCorrectFlags = db.Operations
    // get days that are "active"
    .Where( op => op.IsActive && days.Contains( op.Day ) )
    // join with ObjectA's to filter for active ObjectA's
    // is there a nav property you could use instead?
    // use GroupJoin for use with `Any(...)` in results
    .GroupJoin( db.ObjectA, op => op.Day, oa => oa.Day, ( op, oaGroup ) => new
        {
            //Operation = op,
            // projecting Operation.Day since that's what your foreach loop is using
            Day = op.Day,
            IsLogicACorrect = oaGroup.Any( oa => oa.ObjectACount == 5 ),
            // if IsLogicBCorrect can be determined from the collection of ObjectA's:
            //IsLogicBCorrect = oaGroup.Any( oa => oa.ObjectBCount == 3 ),
        } );

The results are an IQueryable of an anonymous type that maps an "active" Operation.Day with your logic for IsLogicACorrect . 结果是一个匿名类型的IQueryable ,该类型将您的IsLogicACorrect逻辑映射为“活动” Operation.Day For your other IsLogicXCorrect flags, if they can all be determined using the ObjecetA group aoGroup , simply add them to the GroupJoin result selector (as shown in the commented-out property). 为了您的其他IsLogicXCorrect标志,如果他们都可以使用确定ObjecetAaoGroup ,只需将它们添加到GroupJoin结果选择(如注释掉的属性中显示)。 If those flags need their own groupings (eg need to use ObjectB group to determine IsLogicBCorrect , then add additional calls to GroupJoin as shown above but using their respective DbSet and properties. For example, if you need to use db.ObjectB for IsLogicBCorrect : 如果这些标志需要自己的分组(如需要使用ObjectB组确定IsLogicBCorrect ,再加入额外调用GroupJoin如上,但使用各自的显示DbSet和属性。例如,如果你需要使用。 db.ObjectBIsLogicBCorrect

var activeDaysIsLogicCorrectFlags =
    <existing logic from above>
    .GroupJoin( db.ObjectB, at => at.Day, ob => ob.Day, ( at, obGroup ) => new
        {
            // project all previous results
            at.Day,
            at.IsLogicACorrect,
            // new flag
            IsLogicBCorrecet = obGroup.Any( ob => ob.ObjectBCount == 3 ),
        } );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM