Использование методов Linq для навигации по нескольким объектам Entity Framework с предложением Where
Я пытаюсь сделать запрос по нескольким объектным отношениям, используя объектный запрос.
Цепочка сущностей в основном представляет собой OMRMARKET (один ко многим) СВОЙСТВА (один ко многим) OMRBUILDINGSURVEYS (один ко многим) ПЕРИОДЫ. Или, другими словами, у Рынка много свойств, у свойств много опросов, в опросах много периодов.
Я хочу отфильтровать следующий объектный запрос:
OMRMarketsQuery = OMRMarketsQuery.Include("Properties.OMRBuildingSurveys")
Идентификатор периода (псевдокод) OMRMarket.Properties.OMRBuildingSurveys.PeriodID > 50
Тогда я подумал, что мог бы вложить следующие функции Where, такие как:
OMRMarketsQuery = OMRMarketsQuery.Include("Properties.OMRBuildingSurveys").Where(
Function(m) m.Properties.Where(Function(p) p.OMRBuildingSurveys.Where(Function(s)
s.PeriodID > 50)))
И я получаю поддержку intellisense, которая помогает мне создать этот запрос, но затем я получаю ошибку
Значение типа "System.Collections.Generic.IEnumerable(Of OMR.OMRInterfaceCustomCode.OMRBuildingSurvey)" не может быть преобразовано в "Boolean"
Любая помощь будет принята с благодарностью. Я знаю, что это должно быть выполнимо. Большое спасибо заранее.
2 ответа
Хорошо, ответ прост.
Вы не можете фильтровать при использовании Eager Loading или Lazy Loading в этом отношении. Я и несколько фрилансеров перепробовали все виды методов, но ответом было загрузить рынки и свойства, а затем закомментировать следующую строку кода:
'OMRMarketsQuery = OMRMarketsQuery.Include ("Properties.OMRBuildingSurveys")
Чтобы загрузить детали опроса, мы поймали событие изменения списка выбора объектов, и именно здесь мы могли бы выполнить фильтрацию следующим образом:
Private Sub Lbx_PropsByNameSelector_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles Lbx_PropsByNameSelector.SelectionChanged
Dim propertyAdListBox = CType(sender, ListBox)
Dim selectedProperty = CType(propertyAdListBox.SelectedItem, OMRInterfaceCustomCode.Property)
If Not IsDBNull(selectedProperty) Then
Dim RSurveysQuery = From r In OMRInterfaceEntities.OMRBuildingSurveys Where r.PeriodID > 80 And r.PropertyID = selectedProperty.ID
Dim RSurveysList = RSurveysQuery.ToList
If RSurveysList.Any() Then
Dim RecentSurveysSource = CType(Me.FindResource("OMRMarketsPropertiesOMRBuildingSurveysViewSource"), CollectionViewSource)
RecentSurveysSource.Source = RSurveysList
End If
End If
End Sub
Нам очень трудно "отладить" ваш LinQ
без доступа к вашему коду. Тем не менее, когда я пишу сложные LinQ
Запросы, я всегда пытаюсь построить каждый последовательный шаг за раз, так что если я получаю сообщение об ошибке, я знаю, что это происходит от последнего бита, который я добавил. Кроме того, обратите пристальное внимание на требуемые типы ввода и возврата LinQ
методы, которые вы вызываете.
Например, ваша ошибка говорит о том, что часть вашего запроса ожидает Boolean
тип, а не 'System.Collections.Generic.IEnumerable(Of OMR.OMRInterfaceCustomCode.OMRBuildingSurvey)
типа... единственное обязательное Boolean
значения, которые я вижу в вашем запросе, взяты из Where
метод:
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
Поэтому я могу только предположить, что часть вашего запроса возвращает коллекцию OMRBuildingSurvey
объекты вместо необходимых Func<TSource, bool>
сказуемое. Если мы посмотрим на эту часть p.OMRBuildingSurveys.Where(Function(s) s.PeriodID > 50)
мы можем видеть, что это вернет IEnumerable
из OMRBuildingSurvey
экземпляры, которые удовлетворяют условию предиката.
Тем не менее, этот результирующий сбор подается в m.Properties.Where
пункт, который также ожидает Func<TSource, bool>
предикат... так что, похоже, мы нашли ошибку.
ОБНОВЛЕНИЕ >>>
Хорошо... вопреки моему лучшему суждению, я попробую, слепо, как и я, к структуре ваших классов.
Начиная с правой стороны, мы имеем p.OMRBuildingSurveys.Where(Function(s)
s.PeriodID > 50)
мы узнали, возвращает IEnumerable
из OMRBuildingSurvey
экземпляры, которые удовлетворяют условию предиката. Итак, что дальше для этой коллекции?
Нам нужно найти Property
объекты, которые содержат любой из этих OMRBuildingSurvey
экземпляры:
m.Properties.Where(Function(p) p.OMRBuildingSurveys.Intersect(p.OMRBuildingSurveys.
Where(Function(s) s.PeriodID > 50)).Any())
Я даже не уверен, сработает ли это... то, что мы пытаемся сделать, это вернуть IEnumerable
типа Property
содержащий предметы, которые имеют какой-либо из OMRBuildingSurvey
случаи, которые выполняют PeriodID
условие предиката в их OMRBuildingSurveys
(CLR) собственность. Intersect
метод объединяет значение каждого OMRBuildingSurveys
свойство с выходом IEnumerable
из OMRBuildingSurvey
случаи, которые удовлетворяют условию предиката и Any
возвращает все то же самое.
Последний шаг будет примерно таким:
var query = OMRMarketsQuery.Include("Properties.OMRBuildingSurveys").Where(Function(m)
m.Properties.Intersect(m.Properties.Where(Function(p) p.OMRBuildingSurveys.
Intersect(p.OMRBuildingSurveys.Where(Function(s) s.PeriodID > 50)).Any())).Any())
Я в основном сделал то же самое... использовал предыдущий "запрос пока" в качестве входного параметра для Intersect
метод вызывается на OMRBuildingSurvey.Properties
имущество. Теперь я надеюсь, что это сработает, потому что у меня больше нет на это времени. Кроме того, VB может быть выключен, потому что я пишу на C#, но я верю, что вы можете дополнить его информацией, которую я предоставил, если этот пример не работает... эти запросы не так уж плохи, когда вы их нарушаете вниз, как я сделал.
Кстати, этот пример соответствует требованию в вашем вопросе, а не в вашем последнем комментарии.