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

Entity Framework - Stop Lazy Загрузка похожих объектов по запросу?

У меня есть Entity Framework, и он отлично работает в большинстве случаев, когда мне это нужно. У меня есть такая структура

public partial class Topic : Entity
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
    public virtual Post LastPost { get; set; }
    public virtual Category Category { get; set; }
    public virtual IList<Post> Posts { get; set; }
    public virtual IList<TopicTag> Tags { get; set; }
    public virtual MembershipUser User { get; set; }
    public virtual IList<TopicNotification> TopicNotifications { get; set; }
    public virtual IList<Favourite> Favourites { get; set; }
    public virtual Poll Poll { get; set; }
}

Как вы можете видеть, у меня есть ряд связанных объектов, которые являются списками. Они отображаются как стандартные и ленивы загружены, поэтому я могу вызвать Topic.Posts или Topic.TopicNotifications и т.д. (Сопоставления ниже)

HasOptional(t => t.LastPost).WithOptionalDependent().Map(m => m.MapKey("Post_Id"));
HasOptional(t => t.Poll).WithOptionalDependent().Map(m => m.MapKey("Poll_Id"));            
HasRequired(t => t.Category).WithMany(t => t.Topics).Map(m => m.MapKey("Category_Id"));
HasRequired(t => t.User).WithMany(t => t.Topics).Map(m => m.MapKey("MembershipUser_Id"));
HasMany(x => x.Posts).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete();
HasMany(x => x.TopicNotifications).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete();
HasMany(t => t.Tags)
    .WithMany(t => t.Topics)
    .Map(m =>
                {
                    m.ToTable("Topic_Tag");
                    m.MapLeftKey("TopicTag_Id");
                    m.MapRightKey("Topic_Id");
                });

Это все хорошо. Но в нескольких случаях мне нужно вручную заполнить темы. Пост и тема. Затрачены.

Но если я попытаюсь установить Topic.Posts = SomeCollection, он запускает ленивую загрузку и сначала загружает все записи, а затем позволяет мне установить мою коллекцию, поэтому я получаю два набора исполняемых sql (первое, что мне не нужно)

В любом случае, отключить ленивую загрузку вручную по требованию только тогда, когда я хочу установить коллекцию вручную?

Надеюсь, что это имеет смысл...:/

4b9b3361

Ответ 1

Лучше отключить ленивую загрузку по умолчанию и вместо этого указать, когда вы хотите загрузить дополнительные данные в первую очередь. EF настроен таким образом, чтобы позволить загрузку Eager с помощью функции .Include() в вашем запросе, при ленивой загрузке она может стать беспорядочной, если вы начнете включать/выключать ее для различных функций, вам лучше просто отключить ее и управлять что/когда вы хотите, чтобы данные загружались, если вы чувствуете необходимость отключить его.

См. https://msdn.microsoft.com/en-nz/data/jj574232.aspx для конкретных примеров и разбивку различных способов, которыми вы можете получать/ленивые данные загрузки. Первый пример показывает, как вы могли бы удалять сообщения из блога, которые похожи на то, что вы хотите достичь.

var topics = context.Topics 
                      .Include(t => t.Posts) 
                      .ToList(); 

Ответ 2

Мне не известно о подходе, ориентированном на этот точный сценарий, поэтому мне нужно будет временно отключить/включить ленивую загрузку.

using(var context = new MyContext())
{
    context.Configuration.LazyLoadingEnabled = false;
    // do your thing using .Include() or .Load()
    context.Configuration.LazyLoadingEnabled = true;
}

Обратите внимание, что это глобальная конфигурация, поэтому может возникнуть проблема с concurrency, если это происходит в вашем сценарии.

Ответ 3

Я бы не рекомендовал отключать загрузочную загрузку по запросу. Как предлагает AllMadHare, вы можете полностью отключить ленивую загрузку, но это может повлиять на то, как вы загружаете все данные. Я бы рекомендовал удалить ключевое слово virtual из Posts, чтобы ваш класс выглядел так:

public partial class Topic : Entity
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
    public virtual Post LastPost { get; set; }
    public virtual Category Category { get; set; }
    public IList<Post> Posts { get; set; }
    public virtual IList<TopicTag> Tags { get; set; }
    public virtual MembershipUser User { get; set; }
    public virtual IList<TopicNotification> TopicNotifications { get; set; }
    public virtual IList<Favourite> Favourites { get; set; }
    public virtual Poll Poll { get; set; }
}

В документации, найденной здесь: https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazyOffProperty, это позволит вам ленить загружать все другие свойства навигации и загружать сообщения, если вам нужно.

Ответ 4

Поскольку вы используете ленивую загрузку, для ваших классов и свойств коллекции должны быть созданы прокси.

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

Я бы рекомендовал либо использовать прокси/ленивую загрузку, либо отказаться от идеи замены коллекций, либо отступить от использования прокси и получить полный контроль над сгенерированными классами POCO.

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