【问题标题】:Add conditions after muilti join LINQ expression在多连接 LINQ 表达式后添加条件
【发布时间】:2019-08-02 23:13:48
【问题描述】:

我有一个带有 5 个连接/表的 Linq 查询,具有预定义的条件。 因为我需要多次查询,所以我创建了一个函数,该函数将默认 LINQ 查询作为 IQueryable 返回。

public static IQueryable<MroomLinqModel> GetDefaultQuery(CustomerContext CustomerCtx)
{
        var Mrooms = (from mr in CustomerCtx.Mrooms
                      join m in CustomerCtx.Moves on mr.MoveId equals m.MoveId
                      join mg in CustomerCtx.mgroup on m.MgroupId equals mg.MgroupId
                      join s in CustomerCtx.Status on m.StatusId equals s.StatusId
                      join rt in CustomerCtx.Roomtypes on mr.RoomtypeId equals rt.Key
                      join g in CustomerCtx.Guests on m.Mgroup.GuestId equals g.GuestId

                      where
                      Math.Abs(mg.Status) != (int)IResStatus.InComplete &&
                      s.Visible

                      select new MroomLinqModel
                      {
                          OpenDepositPayments = mg.DepositPayments.Any(dp => !dp.Paid),
                          RoomHidden = (mr.RoomId == null ? true : mr.Room.Hidden),
                          StatusVisible = s.Visible,

                          MroomId = mr.MroomId,
                          MoveId = m.MoveId,
                          MgroupId = mg.MgroupId,
                          StatusId = s.StatusId,
                          StatusFlags = s.Flags,
                          BackgroundColor = s.Background_Argb,
                          TextColor = s.Foreground_Argb,
                          PersonCount = m.Movegroups.Sum(m => m.PersonCount),
                          MoveCount = mg.Moves.Count(),

                          RoomId = mr.RoomId,
                          PMSMroomId = mr.PMS_Id,
                          PMSMoveId = m.PMS_Id,
                          PMSMgroupId = mg.MgroupId_Casablanca,

                          From = mr.From,
                          Until = mr.Until,

                          EditableState = m.EditableState,
                          MroomStatus = mr.Status,
                          RoomtypeUsage = mr.Roomtype.Usage,

                          BookingReference = mg.ReferenceNumber,

                          Guest = g
                      });

        return Mrooms;
}

现在我想在之后添加一些条件,例如:

Query = GetDefaultQuery.Where(q => !q.RoomHidden && q.From <= dtLoadEnd && dtLoadStart <= q.Until);
Query = Query.Where(q => q.RoomtypeUsage == RoomtypeUsageType.Roomplan);

这很好用,但执行起来需要更多时间,就像我将所有条件直接添加到第一个 LINQ 查询一样。

如何形成查询以访问原始表并生成快速查询?

【问题讨论】:

  • 连接使用大量内存并减慢查询速度。您可以通过在连接之前添加 where 来加快查询速度:在 m.MgroupId.Where(x => Math.Abs​​(x.Status) != (int)IResStatus.InComplete) 上的 CustomerCtx.mgroup 中加入 mg 等于mg.MgroupId
  • 您在Mrooms 上没有导航属性,允许您选择mr.Status.Flags 而不是使用显式连接?

标签: c# performance entity-framework linq


【解决方案1】:

由于您的所有条件都与您要加入其他表的表匹配,因此您可以在多连接之前添加条件,我为您提供了 2 条建议,要么创建另一个过滤预定义条件的方法,要么添加到您的方法可选过滤器像这样:

public static IQueryable<MroomLinqModel> GetDefaultQuery(CustomerContext CustomerCtx, bool? roomHidden, DateTime? dtLoadEnd 
 /* you can add more parameters but for demonstrations purposes i'm only describing this 2*/)
{
        var query = CustomerCtx.Mrooms;

        if(roomHidden.HasValue)
        {
           query = query.Where( q=>q.From == roomHidden.Value)
        }

        if(dtLoadEnd  .HasValue)
        {
           query = query.Where( q=>q.RoomHidden <= dtLoadEnd.Value)
        }
        // you can add more conditions 

        var Mrooms = (from query 
                      join m in CustomerCtx.Moves on mr.MoveId equals m.MoveId
                      join mg in CustomerCtx.mgroup on m.MgroupId equals mg.MgroupId
                      join s in CustomerCtx.Status on m.StatusId equals s.StatusId
                      join rt in CustomerCtx.Roomtypes on mr.RoomtypeId equals rt.Key
                      join g in CustomerCtx.Guests on m.Mgroup.GuestId equals g.GuestId

                      where
                      Math.Abs(mg.Status) != (int)IResStatus.InComplete &&
                      s.Visible

                      select new MroomLinqModel
                      {
                          OpenDepositPayments = mg.DepositPayments.Any(dp => !dp.Paid),
                          RoomHidden = (mr.RoomId == null ? true : mr.Room.Hidden),
                          StatusVisible = s.Visible,

                          MroomId = mr.MroomId,
                          MoveId = m.MoveId,
                          MgroupId = mg.MgroupId,
                          StatusId = s.StatusId,
                          StatusFlags = s.Flags,
                          BackgroundColor = s.Background_Argb,
                          TextColor = s.Foreground_Argb,
                          PersonCount = m.Movegroups.Sum(m => m.PersonCount),
                          MoveCount = mg.Moves.Count(),

                          RoomId = mr.RoomId,
                          PMSMroomId = mr.PMS_Id,
                          PMSMoveId = m.PMS_Id,
                          PMSMgroupId = mg.MgroupId_Casablanca,

                          From = mr.From,
                          Until = mr.Until,

                          EditableState = m.EditableState,
                          MroomStatus = mr.Status,
                          RoomtypeUsage = mr.Roomtype.Usage,

                          BookingReference = mg.ReferenceNumber,

                          Guest = g
                      });

        return Mrooms;
}

【讨论】:

    【解决方案2】:

    期望 CustomerCtx.MroomsDbSet&lt;Mroom&gt; 并且 Mroom 看起来像:

    public class Mroom {
        public int MroomId {get; set;}
    
        [ForeignKey("Move")]
        public int MoveId {get; set;}         //FK
        public virtual Move Move {get; set;}  //Navigation property 
                                              //configuration may be needed cf annotation
        [ForeignKey("Status")]        
        public int StatusId {get; set;}
        public virtual Status Status {get; set;}
    
        //... Mgroup, Guest, ...
    }
    

    如果不是这样,我建议你重构代码以使用导航属性。

    那么你可以使用PredicateBuilderlinqkit 如下:

    public static IQueryable<MroomLinqModel> GetDefaultQuery(CustomerContext CustomerCtx, Expression<Function<Mroom, bool>> q)
    {
        Expression<Function<Mroom, bool>> w = PredicateBuilder.New<Mroom>
           (s => Math.Abs(s.Mgroup.Status) != (int)IResStatus.InComplete &&
           s.Visible);
        w = w.And(q);
    
        return 
            CustomerCtx.Mrooms.
            Where(w.Expand()).
            Select( x => new MroomLinqModel
            {
                OpenDepositPayments = x.Mgroup.DepositPayments.Any(dp => !dp.Paid),
                RoomHidden = (x.RoomId == null ? true : x.Room.Hidden),
                StatusVisible = x.Status.Visible,
                MroomId = x.MroomId,
                MoveId = x.MoveId,
                MgroupId = x.MgroupId,
                StatusId = x.Status.StatusId,
                StatusFlags = x.Status.Flags,
                BackgroundColor = x.Status.Background_Argb,
                TextColor = x.Status.Foreground_Argb,
                PersonCount = x.Move.Movegroups.Sum(m => m.PersonCount),
                MoveCount = x.Mgroup.Moves.Count(),
                RoomId = x.RoomId,
                PMSMroomId = x.PMS_Id,
                PMSMoveId = x.Move.PMS_Id,
                PMSMgroupId = x.Mgroup.MgroupId_Casablanca,
    
                From = x.From,
                Until = x.Until,
    
                EditableState = x.Move.EditableState,
                MroomStatus = x.Move.Status,
                RoomtypeUsage = mr.Roomtype.Usage,
    
                BookingReference = x.Mgroup.ReferenceNumber,
                Guest = x.Guest
            }
        );
    }
    

    并将其用作:

    GetDefaultQuery(ctx, q => !q.RoomHidden && q.From <= dtLoadEnd && dtLoadStart <= q.Until);
    

    和或

    Expression<Function<Mroom, bool>> w = PredicateBuilder.New<Mroom>(q =>
        !q.RoomHidden && q.From <= dtLoadEnd && dtLoadStart <= q.Until);
    //some logic
    w = w.And(q => q.RoomtypeUsage == RoomtypeUsageType.Roomplan);
    GetDefaultQuery(ctx, w);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多