LINQ to SQL прави заявки за една и съща колона няколко пъти

Имам куп параметри, които подавам в C# метод, който използва LINQ към SQL. Всички тези параметри са филтри от потребителски интерфейс. Четири от параметрите, които трябва да филтрирам, са в същата колона в същата таблица. Например таблицата може да изглежда така:

ID | FK_ID | Name | Value

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

Трябва да взема параметрите на филтъра и да ги съпоставя с колоната Стойност и също така да се уверя, че името е правилно. В момента правя това, като се присъединявам към една и съща маса няколко пъти...но се опасявам, че това е твърде неефективно. Кой е най-добрият начин да направите това? Мисля, че бих искал да изградя заявката динамично, за да мога да проверя кои филтри са зададени, но се боря с това как да изградя своя набор от резултати. В момента изглежда така: (FYI 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