【问题标题】:How to combine a multi-part LINQ to Entities query如何组合多部分 LINQ to Entities 查询
【发布时间】:2011-12-01 11:31:06
【问题描述】:

我在 Stack Exchange 的 Code Review(测试版)上发布了这段代码 sn-p,以获得有关如何最好地重构多部分 LINQ 查询的一些反馈。

对于LINQ 来说相对较新,我不确定从哪里开始查询。

如果有人可以就在该方法中组合一些 LINQ 查询给我任何建议,我将不胜感激;尤其是 'exclude' IQueryable 集合到主查询中(参见 cmets)。

该查询目前的性能不是特别好,如果您提供任何建议以从代码角度提高其性能,我们将不胜感激。

在 Code Review 中收到的 cmets 更具架构性,但我目前无法将任何内容移至数据库。

我很欣赏这是一个很大的方法,但我已经发布了全部内容以提供上下文。

提前感谢您提供的任何建议。

方法

    /// Get templates by username and company 
    public List<BrowsingSessionItemModel> GetItemBrowsingSessionItems( 
        int companyId, 
        string userName, 
        Boolean hidePendingDeletions, 
        Boolean hideWithAppointmentsPending, 
        Boolean hideWithCallBacksPending, 
        int viewMode, 
        string searchString, 
        List<int?> requiredStatuses, 
        List<int?> requiredSources, 
        string OrderBy, 
        BrowsingSessionLeadCustomField fieldFilter) 
    { 

        try 
        { 
            IQueryable<Lead> exclude1; 
            IQueryable<Lead> exclude2; 
            IQueryable<Lead> exclude3; 

            //To prepare call backs pending 
            if (hideWithCallBacksPending == true) 
            { 
                exclude1 = (from l1 in db.Leads 
                            where (l1.Company_ID == companyId) 
                            from l2 // Hiding Pending Call Backs 
                                 in db.Tasks 
                                 .Where(o => (o.IsCompleted ?? false == false) 
                                     && (o.TaskType_ID == (int)RecordEnums.TaskType.PhoneCall) 
                                     && (o.Type_ID == (int)RecordEnums.RecordType.Lead) 
                                     && (o.Item_ID == l1.Lead_ID) 
                                     && (o.Due_Date > EntityFunctions.AddDays(DateTime.Now, -1)) 
                                 ) 
                            select l1); 
            } 
            else 
            { 
                exclude1 = (from l1 in db.Leads 
                            where (0 == 1) 
                            select l1); 
            } 
            //To prepare appointments backs pending 
            if (hideWithAppointmentsPending == true) 
            { 
                exclude2 = (from a1 in db.Leads 
                            where (a1.Company_ID == companyId) 
                            from a2 // Hiding Pending Appointments 
                                 in db.Tasks 
                                 .Where(o => (o.IsCompleted ?? false == false) 
                                     && (o.TaskType_ID == (int)RecordEnums.TaskType.Appointment) 
                                     && (o.Type_ID == (int)RecordEnums.RecordType.Lead) 
                                     && (o.Item_ID == a1.Lead_ID) 
                                     && (o.Due_Date > EntityFunctions.AddDays(DateTime.Now, -1)) 
                                 ) 
                            select a1); 
            } 
            else 
            { 
                exclude2 = (from a1 in db.Leads 
                            where (0 == 1) 
                            select a1); 
            } 
            //To prepare deletions 
            if (hidePendingDeletions == true) 
            { 
                exclude3 = (from d1 in db.Leads 
                            where (d1.Company_ID == companyId) 
                            from d2 // Hiding Pending Deletions 
                                 in db.LeadDeletions 
                                 .Where(o => (o.LeadId == d1.Lead_ID)) 
                            select d1); 
            } 
            else 
            { 
                exclude3 = (from d1 in db.Leads 
                            where (0 == 1) 
                            select d1); 
            } 

            // MAIN QUERY <--
            IQueryable<Lead> list = (from t1 in db.Leads 
                        from t2 
                        in db.LeadSubOwners 
                        .Where(o => t1.Lead_ID == o.LeadId && o.Expiry >= DateTime.Now) 
                        .DefaultIfEmpty() 
                        where (t1.Company_ID == companyId) 
                        where ((t2.Username == userName) && (viewMode == 1)) || ((t1.Owner == userName) && (viewMode == 1)) || ((viewMode == 2)) // Either owned by the user or mode 2 (view all) 

                        select t1).Except(exclude1).Except(exclude2).Except(exclude3); 


            // Filter sources and statuses seperately 

            if (requiredStatuses.Count > 0) 
            { 
                list = (from t1 in list 
                        where (requiredStatuses.Contains(t1.LeadStatus_ID)) 
                        select t1); 
            } 
            if (requiredSources.Count > 0) 
            { 
                list = (from t1 in list 
                        where (requiredSources.Contains(t1.LeadSource_ID)) 
                        select t1); 
            } 



            // Do custom field filter here 
            if (fieldFilter != null) 
            { 
                string stringIntegerValue = Convert.ToString(fieldFilter.IntegerValue); 

                switch (fieldFilter.FieldTypeId) 
                { 

                    case 1: 
                        list = (from t1 in list 
                                from t2 
                                in db.CompanyLeadCustomFieldValues 
                                .Where(o => t1.Lead_ID == o.Lead_ID && fieldFilter.TextValue == o.LeadCustomFieldValue_Value) 
                                select t1); 
                        break; 
                    case 2: 
                        list = (from t1 in list 
                                from t2 
                                in db.CompanyLeadCustomFieldValues 
                                .Where(o => t1.Lead_ID == o.Lead_ID && stringIntegerValue == o.LeadCustomFieldValue_Value) 
                                select t1); 
                        break; 
                    default: 
                        break; 
                } 
            } 

            List<Lead> itemsSorted; // Sort here 

            if (!String.IsNullOrEmpty(OrderBy)) 
            { 
                itemsSorted = list.OrderBy(OrderBy).ToList(); 
            } 
            else 
            { 
                itemsSorted = list.ToList(); 
            } 


            var items = itemsSorted.Select((x, index) => new BrowsingSessionItemModel 
            { 
                Id = x.Lead_ID, 
                Index = index + 1 
            });  

            return items.ToList(); 
        } 
        catch (Exception ex) 
        { 

            logger.Info(ex.Message.ToString()); 
            return new List<BrowsingSessionItemModel>(); 
        } 
    } 

【问题讨论】:

  • 看来你的代码太复杂了。它应该被重新分解。我同意你的看法。
  • 这是where (0 == 1)吗?您可以以与构建过滤器相同的方式有条件地定义例外。如果 SQL 是性能问题,请检查管理工作室中执行的 SQL 查询和测量。

标签: c# asp.net-mvc linq entity-framework linq-to-entities


【解决方案1】:

我不明白这是为什么:

false == false

还有:

where (0 == 1)

那么对于排除 1 和 2:

            //To prepare call backs pending 
            var phoneCallTypeId = (int) RecordEnums.TaskType.PhoneCall;
            var exclude1 = GetExclude(hideWithCallBacksPending, companyId, phoneCallTypeId);

            //To prepare appointments backs pending       
            var appointmentTypeId = (int) RecordEnums.TaskType.Appointment;
            var exclude2 = GetExclude(hideWithCallBacksPending, companyId, appointmentTypeId);

使用以下 GetExclude 方法:

    private object GetExclude(bool hideWithCallBacksPending, int companyId, int typeId)
    {
        return hideWithCallBacksPending
                   ? (from l1 in db.Leads
                      where (l1.Company_ID == companyId)
                      from l2
                          // Hiding Pending Call Backs 
                          in
                          db.Tasks.Where(
                              o =>
                              (o.IsCompleted ?? false) &&
                              (o.TaskType_ID == typeId) &&
                              (o.Type_ID == (int) RecordEnums.RecordType.Lead) &&
                              (o.Item_ID == l1.Lead_ID) &&
                              (o.Due_Date > EntityFunctions.AddDays(DateTime.Now, -1)))
                      select l1)
                   : (from l1 in db.Leads where (0 == 1) select l1);
    }

排除3:

            //To prepare deletions    
            var exclude3 = hidePendingDeletions
                           ? (from d1 in db.Leads
                              where (d1.Company_ID == companyId)
                              from d2
                                  // Hiding Pending Deletions           
                                  in db.LeadDeletions.Where(o => (o.LeadId == d1.Lead_ID))
                              select d1)
                           : (from d1 in db.Leads where (0 == 1) select d1);

排除 1 和 2 可以称为内联,因为它们很短:

// Either owned by the user or mode 2 (view all)      
...select t1)
    .Except(GetExclude(hideWithCallBacksPending, companyId, phoneCallTypeId))
    .Except(GetExclude(hideWithCallBacksPending, companyId, appointmentTypeId))
    .Except(exclude3);

【讨论】:

  • 我猜你最初发布的代码也有同样的问题,对吧?
  • 是的。三元运算符周围缺少一个括号,而且我刚刚返回 IQueryable 并修复了它。再次感谢您。
猜你喜欢
  • 1970-01-01
  • 2023-04-07
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多