LINQ to SQL, запрашивающий один и тот же столбец несколько раз

У меня есть набор параметров, которые я передаю методу C#, использующему LINQ to SQL. Все эти параметры являются фильтрами пользовательского интерфейса. Четыре параметра, которые мне нужно отфильтровать, находятся в одном столбце той же таблицы. Например, таблица может выглядеть так:

ID | FK_ID | Name | Value

1 1 Param1 p1Val
2 1 Param2 p2Val
3 1 Param3 p3.Val
3 1 Param4 p4.Val

Мне нужно взять параметры фильтра и сопоставить их со столбцом «Значение», а также убедиться, что имя указано правильно. В настоящее время я делаю это, присоединяясь к одной и той же таблице несколько раз... но я боюсь, что это слишком неэффективно. Как лучше всего это сделать? Я думаю, что хотел бы построить запрос динамически, чтобы я мог проверить, какие фильтры установлены, но я борюсь с тем, как мне построить свой набор результатов. Прямо сейчас это выглядит так: (к вашему сведению, ContextProperties - это рассматриваемая таблица)

var result = 

from f in dataContext.Faults
join m in dataContext.Messages on f.FaultID equals m.FaultID              
join c in dataContext.ContextProperties on m.MessageID equals c.MessageID
join cp in dataContext.ContextProperties on c.MessageID equals cp.MessageID
join cpp in dataContext.ContextProperties on cp.MessageID equals cpp.MessageID
join cppp in dataContext.ContextProperties on cpp.MessageID equals cppp.MessageID
where (f.DateTime >= initDate && f.DateTime <= finishDate) &&
                     f.FaultID == (faultID != Guid.Empty ? faultID : f.FaultID) &&
                     f.Application == (!string.IsNullOrEmpty(application) ? application : f.Application) &&
                     f.FaultCode == (!string.IsNullOrEmpty(faultCode) ? faultCode : f.FaultCode) &&
                     f.FailureCategory == (!string.IsNullOrEmpty(failureCategory) ? failureCategory : f.FailureCategory) &&
                     f.ErrorType == (!string.IsNullOrEmpty(errorType) ? errorType : f.ErrorType) &&
                     (f.FaultSeverity >= 0 && f.FaultSeverity <= maxFaultSeverity)
                     where (c.Value.ToString() == (!string.IsNullOrEmpty(geniusReference) ? geniusReference : c.Value.ToString())
                        && c.Name.ToString() == "GeniusReference") 
                     where (cp.Value.ToString() == (!string.IsNullOrEmpty(programNumber) ? programNumber : cp.Value.ToString())
                        && cp.Name.ToString() == "ProgramGeniusNumber")
                     where (cpp.Value.ToString() == (!string.IsNullOrEmpty(platform) ? platform : cpp.Value.ToString())
                        && cpp.Name.ToString() == "Platform")
                     where (cppp.Value.ToString() == (!string.IsNullOrEmpty(modifiedBy) ? modifiedBy : cppp.Value.ToString())
                        && cppp.Name.ToString() == "ModifiedBy")
                     select new FaultsWithFilters {
                                                    DateTime = f.DateTime
                                                    ,FaultID = f.FaultID
                                                    ,Scope = f.Scope
                                                    ,FaultCode = f.FaultCode
                                                    ,FaultSeverity = f.FaultSeverity
                                                    ,ErrorType = f.ErrorType
                                                    ,Description = f.Description
                                                    ,FaultDescription = f.FaultDescription
                                                    ,FailureCategory = f.FailureCategory
                                                    ,GeniusReference = c.Value.ToString()
                                                    ,ProgramNumber = cp.Value.ToString()
                                                    ,Platform = cpp.Value.ToString()
                                                    ,ModifiedBy = cppp.Value.ToString()
                                                    };

за которым следует куча операторов where и select. Заранее спасибо за помощь! PS извините за дерьмовое форматирование.


person Will Weld    schedule 12.04.2013    source источник
comment
Как вы хотите, чтобы результат выглядел? У меня возникли проблемы с визуализацией этого на основе вопроса в его нынешнем виде.   -  person Matthew Jones    schedule 12.04.2013
comment
Привет, Мэтью, я обновил исходный пост полным запросом в его нынешнем виде. FaultsWithFilters — это собственный класс, который я создал. Достаточно ли обновления для визуализации набора результатов?   -  person Will Weld    schedule 12.04.2013
comment
Итак, вы пытаетесь получить все ContextProperties для данного MessageID, где имя ContextProperties соответствует любому из GeniusReference, ProgramGeniusNumber, Platform, ModifiedBy. Звук правильный?   -  person Matthew Jones    schedule 12.04.2013
comment
Да!... но для данного FaultID. MessageID не предоставляется, но вам нужно MessageID для получения правильных свойств контекста.   -  person Will Weld    schedule 12.04.2013


Ответы (1)


Создавайте свой запрос по одному предложению вместо действительно плохо выглядящего field == (filterSet ? filter : field).

Сначала присоедините все необходимые таблицы:

var query = dataContext.Faults.Join(dataContext.Messages, f => f.FaultID, m => mFaultID, new { f, m })
                              .Join(dataContext.ContextProperties, x => x.m.MessageID, c => c.MessageID, new { x.f, x.m, c });
                              // add all other joins here
                              // and all where conditions that are always valid

Затем добавьте условные where условия:

if(!string.IsNullOrEmpty(geniusReference))
{
    query = query.Where(x => x.c.Value.ToString() == geniusReference);
}

// instead of:
// where (c.Value.ToString() == (!string.IsNullOrEmpty(geniusReference) ? geniusReference : c.Value.ToString())

В конце добавьте проекцию:

var results = from x in query
              select new FaultsWithFilters {
                   DateTime = x.f.DateTime
                  ,FaultID = x.f.FaultID
                  ,Scope = x.f.Scope
                  ,FaultCode = x.f.FaultCode
                  ,FaultSeverity = x.f.FaultSeverity
                  ,ErrorType = x.f.ErrorType
                  ,Description = x.f.Description
                  ,FaultDescription = x.f.FaultDescription
                  ,FailureCategory = x.f.FailureCategory
                  ,GeniusReference = x.c.Value.ToString()
                  ,ProgramNumber = x.cp.Value.ToString()
                  ,Platform = x.cpp.Value.ToString()
                  ,ModifiedBy = x.cppp.Value.ToString()
              };
person MarcinJuraszek    schedule 12.04.2013
comment
Это выглядит великолепно! И намного чище! Я боюсь, что такое количество объединений вызовет проблемы с производительностью. Таблица ContextProperties со временем будет только расти. Является ли выполнение всех этих объединений лучшим вариантом? - person Will Weld; 12.04.2013
comment
Причина, по которой я прошу выполнять все эти соединения, заключается в том, что для каждого из параметров GeniusReference, ProgramGeniusNumber, Platform, ModifiedBy я хочу присоединиться к таблице ContextProperties, только если они установлены, иначе у меня были бы ненужные соединения. - person Will Weld; 12.04.2013