#entity-framework #entity-framework-4.1
#entity-framework #entity-framework-4.1
Вопрос:
Есть ли способ использовать FirstOrDefault()
внутри сложного запроса, но не создавать исключение, если оно возвращает нулевое значение?
Мой запрос:
contex.Table1.Where(t => t.Property == "Value").FirstOrDefault()
.Object.Table2.Where(t => t.Property2 == "Value2").FirstOrDefault();
Если запрос к первой таблице (Table1) не возвращает объект, код выдает исключение. Есть ли способ заставить его возвращать только null?
Комментарии:
1. я не знаю, имеет ли C # / .NET нулевой объект, который может быть возвращен по умолчанию, но вы должны проверить шаблон нулевого объекта
2. Почему бы не использовать 2 запроса вместо 1?
3. Мне нужно сделать это в том же запросе о проблеме производительности
Ответ №1:
Попробуйте SelectMany
включить Table2
, без промежуточного FirstOrDefault()
:
context.Table1.Where(t1 => t1.Property1 == "Value1")
.SelectMany(t1 => t1.Table2.Where(t2 => t2.Property2 == "Value2"))
.FirstOrDefault();
Кроме того, вы можете захотеть использовать SQL Profiler для проверки SQL, отправляемого EF. Я полагаю, что запрос, созданный в вашем вопросе, приведет к отправке двух запросов в базу данных; по одному для каждого FirstOrDefault()
.
Ответ №2:
Вы можете создать свою собственную вспомогательную функцию, которая принимает IEnumerable
public static TSource CustomFirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
return source.FirstOrDefault() ?? new List<TSource>();
}
Это фактически вернет пустой список, который при вызове, указывающий, что ваш код в вашем свойстве Object может обрабатывать нули, не сработает, потому что вы просто вернете коллекцию элементов 0 вместо null .
Комментарии:
1. Это не сработает, поскольку вы пытаетесь вернуть один TSource ИЛИ список <TSource> в зависимости от результата FirstOrDefault() .
Ответ №3:
Только первый запрос с Where
является запросом к базе данных. Как только вы применяете «жадный» оператор, подобный FirstOrDefault
запросу, выполняется. Второй запрос выполняется в памяти. Если Object.Table2
это коллекция (которая, по-видимому, есть), и у вас не включена отложенная загрузка, ваш код завершится сбоем, потому что коллекция есть null
. Если у вас включена отложенная загрузка, второй запрос выполняется автоматически для загрузки коллекции — полная коллекция и фильтр выполняются в памяти.
Вместо этого ваш запрос должен выглядеть как код @adrift, который на самом деле будет только одним запросом к базе данных.