Оптимизация многосекционного LINQ к объектам запроса


Я унаследовала приложение, которое использует LINQ-в-сущности для ОРМ и не имеют большой подверженности этого.

Есть много таких примеров в приложении. Не могли бы вы сказать мне, где начать в рефакторинг этого кода?

Я понимаю, что это большой кусок кода, однако запрос не особенно производительным, и мне интересно, что ты думал, что основные узкие места в этом деле.

    /// <summary>
    /// Get templates by username and company
    /// </summary>
    /// <param name="companyId"></param>
    /// <param name="userName"></param>
    /// <returns></returns>
    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);
            }


            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>();
        }
    }


979
1
задан 30 ноября 2011 в 10:11 Источник Поделиться
Комментарии
1 ответ

Вы правы... это большой кусок кода, который является немного трудно переварить. Что говорит о том, несколько вещей приходят на ум.


  • Во-первых, этот метод является слишком большой. Это не вопрос стиля персе... в этом случае, он настолько велик, что он не будет оптимизированный JIT поскольку образовавшийся Ил будет слишком большой. Разорвать этот вверх на логические подфункций.

  • Я хотел бы предложить вам выталкивать порциями (если не все) этого обратно в базу данных с помощью SPROC, вид, или, скорее, сочетание этих двух. Я хотел бы купить пончики для своей БД, и сделать новый друг.

  • Если это не вариант, я бы упасть обратно в ADO.NET и создать один динамический запрос, который включает в себя все 'исключить' звонки, главном списке звонков, и фильтрации в одном кадре. Это будет немного нудно, но должны обеспечить вам то, что гораздо более производительным. Имейте в виду, что старый стиль ADO.NET от 150%-300% быстрее, то даже самый лучший ОРМ. Это не критика, потому что они действительно интересные, в некоторых областях, особенно если вы можете использовать под кэширование вариантов. Что сказал, это не решение всех проблем.

2
ответ дан 30 ноября 2011 в 08:11 Источник Поделиться