EntityFramework - Стратегии для загрузки дочерних объектов - PullRequest
4 голосов
/ 04 сентября 2010

Я получил 2 следующих объекта: Пользователь и сообщение

Простая версия пользователя:

public virtual int Id { get; set; }
public virtual IList<Post> Posts { get; set; }

Сообщения не загружаются по умолчанию.

В определенных условияхМне нужно загрузить сообщения (например, я хочу посчитать количество сообщений для этого пользователя).Сейчас я добавил вызов метода LoadPosts (пользователь-пользователь) в UserRepository:

_context.LoadProperty(user, "Posts");
  • Есть ли более логичное место для размещения этого метода?
  • Должен ли я положить его в PostRepository?Что-то вроде CountPosts (int userId)?
  • Должен ли я предложить перегрузку моему LoadMethod.Пример: Load(bool loadPosts)

Есть ли способ, что если я пишу myUser.Posts.Count () сообщения загружаются автоматически вместо нуля?

Ответы [ 4 ]

6 голосов
/ 16 октября 2010

Сценарий, который вы описываете, называется отложенной загрузкой и поддерживается EF4.Судя по вашему коду, у вас есть объекты POCO, и, поскольку вы объявили свой список как virtual, EF может создавать прокси для обеспечения отложенной загрузки.Существует настройка, которую вы можете использовать для включения отложенной загрузки: context.ContextOptions.LazyLoadingEnabled = true;.В этом случае всякий раз, когда вы получаете доступ к свойству Posts уже загруженного User, данные будут загружаться из БД.

Более подробная информация здесь, в разделе «Отложенная / отложенная загрузка»: http://blogs.msdn.com/b/adonet/archive/2009/05/28/poco-in-the-entity-framework-part-2-complex-types-deferred-loading-and-explicit-loading.aspx

Причина, по которой это работает, заключается в том, что когда я пометил свое свойство коллекции как виртуальное, это позволило Entity Framework предоставлять экземпляр прокси для моего типа POCO во время выполнения, и именно этот проксивыполняет автоматическую отложенную загрузкуЭкземпляр прокси основан на типе, который является производным от моего собственного класса сущностей POCO, поэтому все предоставленные вами функции сохраняются.С точки зрения разработчика, это позволяет вам писать постоянный невежественный код, даже если отсроченная загрузка может быть требованием.

И кратко в вашем списке мини-вопросов:

  • Есть ли более логичное место для размещения этого метода? - Если вы решите реализовать метод загрузки Posts для данного пользователя самостоятельно, он логически принадлежит UserRepository.
  • Должен ли я положить его в PostRepository?Что-то вроде CountPosts (int userId)? - Может принадлежать PostsRepository в случае, если вы загружаете посты, не связанные с определенным пользователем (например, глобальный поиск по ключевым словам среди всех постов).
  • Должен ли я предложить перегрузку на моем LoadMethod.Пример: Load (bool loadPosts) - Да, вы можете это сделать.Однако с EF вам просто нужно отключить отложенную загрузку.Сообщения будут загружаться вместе с пользователем.
0 голосов
/ 19 октября 2010

Есть ли более логичное место для этого метода?

ИМО, да. У меня не было бы такого конкретного метода, если бы вам не требовалось много сообщений. Я бы Eager Load сообщений по требованию . (Подробнее об этом ниже)

Должен ли я положить его в PostRepository?

Сорт. LoadPosts(User user) - это логин, специфичный для PostRepository, IMO. НО - это очень специфический метод .. это означает, что рано или поздно вы PostRepository будете очень заняты множеством конкретных методов. Обычно у нас есть универсальный репозиторий, который позволяет входить Expressions . Таким образом, вам не нужно создавать множество конкретных методов. У вас может быть один метод, за исключением выражений и извлекающий ваши различные запросы.

например.

IQueryable<Post> Find(Expression<Func<Post, bool>> predicate, 
                      string[] includeAssociations);

Тогда вы можете использовать его, чтобы загружать то, что вам нужно.

например. Получить все сообщения для конкретного пользователя.

var posts = _postRepostitory
    .Find(x => x.UserId = userId, new [] { "User" } )
    .ToList();

или оборотная сторона, для пользователя, получите мне все свои сообщения ...

var user = _userRepository
    .Find(x => x.UserId = userId, new [] { "Posts" } )
    .ToList();

Если вам нужна помощь с кодом внутри метода Find, просто спросите ... но это довольно тривиально.

Идея такова (по порядку, что крайне)

  • выражение только что применено к сущности Post внутри скрытого контекста внутри экземпляра postRespository.
  • Наконец, вы Include для каждой требуемой ассоциации, последняя.

Ничего не запрограммировано. Все это определяется кодером, когда они вызывают метод Find :) Один метод для управления ими всеми.

ПРИМЕЧАНИЕ: Конечно, у меня на самом деле есть 4 - один без аргументов ... вплоть до того, который я показал, с 4 аргументами.

Что-то вроде CountPosts (int userId)?

(непроверенный, псевдо-код .. думая о моей голове)

var count = _postRepostiory
    .Find(x => x.UserId = userId, new [] { "Posts" })
    .Select(x => x.Posts).Count;

Должен ли я предложить перегрузку моему LoadMethod. Пример: Load (bool loadPosts)

Неа. сейчас не нужно.

Есть ли способ, что если я пишу myUser.Posts.Count (), сообщения загружаются автоматически, а не равны нулю?

Да, если вы последуете моим советам выше.

var user = _userRepository
    .Find(x => x.UserId = userId, new [] { "Posts" })
    .SingleOrDefault();

var postCount = user == null || user.Posts == null ? 0 : user.Posts.Count;

Офигеть и программировать, падаван !!

0 голосов
/ 18 октября 2010

Вы должны поместить его в репозиторий, перегрузив или добавив новый метод. Подробнее

Если вы звоните _context.Load() вне хранилища, это может быть неверно .

0 голосов
/ 15 октября 2010

Если вы используете пользовательский поставщик данных, в этом случае я бы предложил вам загрузить данные методом CreateDataSource.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...