1

У меня проблема с добавлением дочернего объекта к родительскому объекту исключительно медленным, когда этого не должно быть. В этом случае есть десятки тысяч дочерних объектов (в этом случае записи 33k), но ни один из них не является дочерним объектом родительского объекта.Медленность Entity Framework, когда должна быть скорость

Когда я добавляю первый ребенок к родителю занимает более одной минуты, чтобы закончить:

public class ParentEntity // POCO generated by EF TT4 templates 
{ 
    public virtual int Id { get; set; } 
    public virtual ICollection<ChildEntity> ChildEntities {} 
} 

public class ChildEntity // POCO generated by EF TT4 templates 
{ 
    public virtual int Id { get; set; } 
    public virtual int ParentEntityId { get; set; } 
    public virtual ParentEntity ParentEntity { get; set; } 
    public virtual Warehouse Warehouse { get; set; } 
    public virtual WarehouseLocation WarehouseLocation { get; set; } 
} 

public class Warehouse { // etc } // another POCO class 
public class WarehouseLocation { // etc } // another POCO class 

// somewhere in a controller action method... 
var parent = _parentEntityService.GetBy(id); 
var child = new ChildEntity{ ParentEntityId = id, 
          WarehouseId = id2, WarehouseLocationId = id3 }; 

// ChildEntities.Add() takes more than one minute to add the 
// first and only child to this parent 
// why would this be so incredibly slow? 

parent.ChildEntities.Add(child); 

Каков наилучший способ приблизиться к поиску проблемы скорости в EntityFramework?

Update: ЭфПроф показывает, что он выдает три SQL запросов:

SELECT * FROM ChildEntities where ParentId = id 
SELECT * FROM ChildEntities where WarehouseId = id2 
SELECT * FROM ChildEntities where WarehouseLocation = id3 

Почему загружать их для каждого ChildEntity, когда это нужно просто загрузить их только для текущего ребенка?

Редактировать 2: Согласно @LadislavMrnka дополнительные запросы вызваны методом Fixup шаблона. Но когда я комментирую эти методы и комментирую звонок Fixup, он все еще медленный. Разве это не правильный способ, чтобы удалить FixUp (похоже, что он удаляется мне):

public class ChildEntity { 
public virtual Warehouse Warehouse 
{ 
    get { return _warehouse; } 
    set 
    { 
     if (!ReferenceEquals(_warehouse, value)) 
     { 
      var previousValue = _warehouse; 
      _warehouse = value; 
      //FixupWarehouse(previousValue); // commented out 
     } 
    } 
} 
+0

Попробуйте изменить это следующим образом: 'var parent = _parentEntityService.GetBy (id); var child = new ChildEntity {Foo = "", Bar = "", Parent = parent}; _ entityService.Save (child) ' –

+0

И используйте EF Profiler (http://efprof.com/), чтобы увидеть внутренность объекта фреймворк. –

+0

Имеет ли этот «родительский» объект большое количество «ChildEntities»? – Eranga

ответ

0

Это помогло мне:

context.Configuration.AutoDetectChangesEnabled = false; 

Я не уверен, если это касается вас тоже, но если я правильно понимаю ваш вопрос, это медленно для вас, когда вы просто делаете Add?

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

Второй способ (если вы используете DbContext) является:

using (var dbCtx = new MyDataContext()) 
{ 
    var ctx = ((IObjectContextAdapter)dbCtx).ObjectContext; 

    var customers = ctx.CreateObjectSet<Customer>(); 

    customers.AddObject(customer); 
} 

Поскольку ObjectContext обрабатывает вещи по-разному внутренне по отношению к изменениям. Я не могу сейчас найти источник, я попытаюсь найти его позже.

5

Это ваша проблема:

var child = new ChildEntity 
       { 
        Foo = "", 
        Bar = "", 
        ParentEntityId = id, 
        WarehouseId = 1, 
        WarehouseLocationId = 1 
       }; 

parent.ChildEntities.Add(child); 

ИМХО это все о FixUp коллекции скрытой в коде, созданный шаблоном POCO. Fixup + ленивая загрузка = проблемы с производительностью. Fixup пытается сделать все в вашей модели синхронно. Это означает, что если вы установите одну сторону свойства навигации или свойство FK, она попытается убедиться, что свойство навигации на противоположной стороне отношения также отражает изменение. Проблема в том, что если свойство навигации не загружено, это вызовет ленивую загрузку. В вашем случае это выглядит как установка склада первый устроилась навигация собственности в ChildEntity и после этого пыталось FixUp свойство навигации по Warehouse инстанциям, но его коллекция дочерних объектов не была загружена => отложенной загрузки, вызывая

SELECT * FROM ChildEntities where WarehouseId = some id 

То же произошло в случае WarehouseLocation. Первый запрос - это результат добавления дочерней к негруженной коллекции родительского объекта.

Решение состоит в том, чтобы изменить шаблон и избавиться от всех исправлений (например, шаблон DbContext POCO для EFv4.1+ не используйте fixups больше) или отключить отложенную загрузку для этой операции по телефону:

context.ContextOptions.LazyLoadingEnabled = false; 

// Your insert logic here 

context.ContextOptions.LazyLoadingEnalbed = true; 

Вы можете даже обернуть код в пользовательских IDisposable как:

public class DisableLazyLoadingScope : IDisposable 
{ 
    private readonly ObjectContext context; 

    public DisableLazyLoadingScope(ObjectContext context) 
    { 
     this.context = context; 
     context.ContextOptions.LazyLoadingEnabled = false; 
    } 

    public void Dispose() 
    { 
     context.ContextOptions.LazyLoadingEnabled = true; 
    } 
} 

И использовать его как:

using (new DisableLazyLoadingScope(context) 
{ 
    // Your insert logic here 
} 
+0

Ага, я понимаю, спасибо. Какую пользу дает Fixup? У меня только это, потому что это было в шаблоне TT4, и я был бы рад удалить его, если он не понадобится. Я использую EF4.1 сейчас, но когда шаблоны были впервые добавлены, я использовал более раннюю версию EF. –

+0

Fixup сохраняет загруженные данные синхронно. Если вы установите 'WarehouseId' с одной стороны, то исправление гарантирует, что свойство навигации' Warehouse' имеет правильный объект 'Warehouse' и сущность' Warehouse' имеет ваш дочерний элемент в своей коллекции связанных объектов. Побочным эффектом является то, что если вы используете ленивую загрузку, он будет загружать эти объекты, даже если вы не хотите их использовать. –

+0

Я удалил исправление из ChildEntity, и он все еще медленный. Теперь я попытаюсь удалить исправление от всех сущностей.Я посмотрел на собственный объект сущности 4.1 отслеживания, и он по-прежнему имеет Fixup (реализован по-разному): 'var previousValue = _warehouse; _warehouse = значение; FixupWarehouse (PreviousValue); OnNavigationPropertyChanged («Warehouse»); ' –

Смежные вопросы