Подтвердить что ты не робот

Использование .Find() &.Include() в том же запросе

У меня есть следующий метод, автоматически созданный из шаблона леса с репозиторием: -

public Group Find(int id)
{
    return context.Groups.Find(id);
}

Но поскольку объект Groups имеет два свойства навигации, которые мне нужны, поэтому я хотел включить .Include, поэтому я заменяю .find на .where: -

public Group Find(int id)
{
    return context.Groups.Where(c=>c.GroupID==id)
                         .Include(a => a.UserGroups)
                         .Include(a2 => a2.SecurityRoles)
                         .SingleOrDefault();
}

Но мой вопрос заключается в том, как я могу применить .Include к .find() вместо использования .Where()?

4b9b3361

Ответ 1

Я просто думал о том, что на самом деле находит. @lazyberezovsky является правильным включать и найти can not использоваться в сочетании друг с другом. Я думаю, что это довольно преднамеренно, и вот почему:

Метод Find в DbSet использует значение первичного ключа, чтобы попытаться найти объект, отслеживаемый контекстом. Если объект не найден в контекст, тогда запрос будет отправлен в базу данных, чтобы найти объект там. Null возвращается, если объект не найден в контексте или в базе данных.

Найти отличается от использования запроса двумя важными способами:

  • Обратная связь с базой данных будет выполняться только в том случае, если объект с указанным ключом не найден в контексте.
  • Найти возвратит объекты, которые находятся в состоянии Добавлен. То есть, Find вернет объекты, которые были добавлены в контекст, но еще не сохранены в базе данных.

(из http://msdn.microsoft.com/en-us/data/jj573936.aspx)

Поскольку find - это оптимизированный метод, он может избежать необходимости поездки на сервер. Это здорово, если вы уже отслеживали объект, поскольку EF может быстрее его вернуть.

Однако если это не только этот объект, который нам нужен (например, мы хотим включить некоторые дополнительные данные), то нет способа узнать, были ли эти данные уже загружены с сервера. В то время как EF, вероятно, может сделать эту оптимизацию в сочетании с соединением, она будет подвержена ошибкам, поскольку она делает предположения о состоянии базы данных.

Я предполагаю, что включение и поиск неспособности к совместному использованию - это очень продуманное решение обеспечить целостность данных и излишнюю сложность. Это намного чище и проще  когда вы хотите сделать соединение, чтобы всегда идти в базу данных для выполнения этого соединения.

Ответ 2

Вы не можете. Найти, определенный в DbSet<T>, и возвращает объект. Вы не можете вызывать Include для сущности, поэтому единственный возможный вариант - вызов Find после Include. Для этого вам нужен DbSet<T>, но Include("UserGroups") вернет DbQuery<T> и Include(g => g.UserGroups) также вернет DbQuery<T>:

public static IQueryable<T> Include<T>(this IQueryable<T> source, string path) 
    where T: class
{
    RuntimeFailureMethods.Requires(source != null, null, "source != null");
    DbQuery<T> query = source as DbQuery<T>;
    if (query != null)    
        return query.Include(path); // your case
    // ...
}

DbQuery<T> не является дочерним элементом DbSet<T>, поэтому метод Find недоступен, Также имейте в виду, что Find сначала ищет объект в локальных объектах. Как он будет включать некоторые ссылочные объекты, если они еще не загружены?