Разница между отложенной загрузкой в ​​NHibernate и Entity Framework - PullRequest
1 голос
/ 24 сентября 2011

Играя с Entity Framework и NHibernate, используя сущности POCO, я сделал следующее наблюдение, которое я нахожу немного необычным:

У меня есть две сущности POCO, 'Order' и 'Product'.Между этими двумя есть отношения многие ко многим.Когда я добавляю товар в заказ, я использую метод FixUp, чтобы гарантировать, что противоположная сторона отношения также обновляется, т. Е. Что также обновляется коллекция товаров в «Заказах».

Мой заказУ объекта POCO есть следующий метод для выполнения FixUp:

private void FixupProducts(object sender, NotifyCollectionChangedEventArgs e)
{
    if(e.NewItems != null)
    {
        foreach(Product p in e.NewItems)
        {
            p.Order.Add(this);
        }
    }
}

При профилировании этого сценария с помощью EFProf и NHProf я заметил, что Entity Framework генерирует еще один оператор SQL, чем NHibernate, причина которого кажетсябыть такой строкой:

p.Order.Add(this);

При использовании Entity Framework приведенная выше строка вызывает выполнение выбора в базе данных для возврата всех заказов на продукт 'p'.Я не ожидаю, что это произойдет, так как я использую ленивую загрузку и на самом деле не хочу получать доступ к коллекции продуктов Order.Я просто хочу добавить к нему заказ.

В NHibernate не делается никаких попыток загрузить набор заказов товаров, если я не пытаюсь получить к нему доступ явно.Например, если я скажу:

foreach(Order o in product.Orders)
{
    Console.WriteLine(o.Id);
}

Итак, в конечном счете, мой вопрос: почему Entity Framework генерирует дополнительный оператор SQL?Есть ли разница в реализации отложенной загрузки для двух платформ, о которых я не знаю?

*** РЕДАКТИРОВАНИЕ В ОРИГИНАЛЕ Кажется, что Entity Framework не ведет себя лениво, когда в коллекции вызывается какой-либо метод.Любая попытка добавить или посчитать (или предположительно любую другую операцию над коллекцией) приводит к загрузке этой коллекции в память.

Что интересно, так это мое сопоставление NHibernate (которое представляет собой пакет с «продуктами», показанными ниже), похоже, ведет себя «очень лениво», хотя мое сопоставление настроено просто как ленивое:

<bag name="Products" cascade ="all"  table="OrderProduct" mutable="true" lazy="true">

Я могу добавить коллекцию, не загружая ее в память.Я думаю, что вызов 'Count' приведет к загрузке заказов, если я не настрою его как 'extra-lazy'.

Может кто-нибудь прокомментировать, правильно ли это?

Ответы [ 2 ]

1 голос
/ 25 сентября 2011

Я думаю, что вызов 'Count' приведет к загрузке заказов, если я не настрою его как 'extra-lazy'.

Это правильно, вызывая Count, а такжеСодержимое будет оптимизировано и не будет загружать всю коллекцию в NHibernate.Вы также можете найти это сравнение EF против NHibernate интересным:

Коллекция с lazy = ”extra” - Lazy extra означает, что NHibernate адаптируется к операциям, которые вы можете выполнять поверхваши коллекции.Это означает, что blog.Posts.Count не будет вызывать загрузку всей коллекции, а скорее создаст «select count (*) из оператора Posts, где BlogId = 1», и что blog.Posts.Contains () также приведет кв одном запросе, вместо того, чтобы платить за загрузку всей коллекции в память.

Добавление нового элемента в неинициализированную ленивую коллекцию не приведет к загрузке коллекции.Это не должно быть отображено как очень ленивый для этого.Взгляните на эту статью :

Теперь для коллекций, сопоставленных с отложенной загрузкой, операции Add () разрешены, даже если коллекция не инициализирована (т.е. коллекция простодействует как прокси).При добавлении объекта в коллекцию в этом состоянии вызывается метод QueueAdd (), который сохраняет добавленный объект во вторичной коллекции.После выполнения отложенной инициализации эта вторичная коллекция объединяется с основной (я полагаю, что это делает метод DelayedAddAll ()).Это может быть трудно отладить, потому что ленивая загрузка запускается прозрачно, если вы просто касаетесь коллекции отладчиком (при условии, что сеанс подключен в этот момент), и все инициализируется правильно.

1 голос
/ 24 сентября 2011

Так работает шаблон EF POCO и его FixUp методы. Единственные способы избежать этого:

  • Удаление FixUp методов из шаблона POCO
  • Временное отключение отложенной загрузки при назначении Product на Order

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

...