Использование FirstOrDefault() в запросе

#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, который на самом деле будет только одним запросом к базе данных.