Ускорение Entity Framework 4.2 POCO - PullRequest
       1

Ускорение Entity Framework 4.2 POCO

5 голосов
/ 17 ноября 2011

Я использую Entity Framework 4.2 и у меня довольно серьезная проблема с производительностью. Я использую подход POCO, унаследованный от DbContext, и вот небольшой пример, который объясняет проблему:

У меня есть база данных, которая имеет 2 таблицы - A и B:

A

  • AId (int - не null - идентификатор - первичный ключ)
  • Имя (nvarchar (50) - не ноль)

B

  • BId (int - не null - идентификатор - первичный ключ)
  • SomeValue (int - не null)
  • AId (int - не ноль - внешний ключ, подключающийся к AId в таблице A)

A содержит одну строку (1, «Test»), а B имеет 6000 строк (SomeValue - это просто число от 0 до 5999) - все из которых ссылаются на строку A через столбец внешнего ключа.

Я создаю edmx из базы данных и выключаю генерацию кода. Затем я создаю следующие классы:

public class DatabaseContext : DbContext
{
    public DatabaseContext(string name) : base(name)
    {
        Configuration.AutoDetectChangesEnabled = false;
        As = Set<A>();
        Bs = Set<B>();
    }

    public DbSet<A> As { get; private set; }
    public DbSet<B> Bs { get; private set; }
}

public class A
{
    public virtual int AId { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<B> Bs { get; private set; }

    public void AddB(B b)
    {
        if (b == null)
        {
            throw new ArgumentNullException("b");
        }

        if (Bs == null)
        {
            Bs = new List<B>();
        }

        if (!Bs.Contains(b))
        {
            Bs.Add(b);
        }

        b.A = this;
    }
}

public class B
{
    public virtual int BId { get; set; }
    public virtual A A { get; set; }
    public virtual int SomeValue { get; set; }
}

Теперь я просто делаю следующее:

var ctx = new DatabaseContext("ScalabilityTestEntities");
var a = ctx.As.FirstOrDefault();
a.Bs.Add(new B { SomeValue = 987 });

Последняя строка (где я добавляю новую букву B) занимает примерно 6 секунд на моем четырехъядерном компьютере с 4 ГБ ОЗУ и 64-разрядной операционной системой Windows 7, на которой база данных работает локально.

Действительно плохая вещь в том, что кажется, что она экспоненциально ухудшается, поскольку, если вы удвоите число строк в B, это займет около 20 секунд!

Буду очень признателен за любые советы, чтобы это произошло быстрее. Большое спасибо!

Ответы [ 2 ]

4 голосов
/ 17 ноября 2011

Мир навигационных свойств может быть болезненным.По сути, нам пришлось отказаться от их использования, потому что они вызывают очень много проблем с производительностью за вашей спиной (особенно когда вы подключаетесь и отключаете сущности, но это другая история)..Bs загружает все B для этого A.

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

3 голосов
/ 17 ноября 2011

В таком случае вам следует отключить отложенную загрузку:

var ctx = new DatabaseContext("ScalabilityTestEntities");
ctx.Configuration.LazyLoadingEnabled = false;
var a = ctx.As.FirstOrDefault();
a.Bs = new List<B>();
a.Bs.Add(new B { SomeValue = 987 });

По умолчанию включена отложенная загрузка (что приводит к загрузке всех 6000 B при доступе к коллекции), поскольку ваша навигационная коллекция объявленакак virtual.Если вам никогда не нужно или вы хотите использовать отложенную загрузку, вам следует полностью удалить ключевое слово virtual или отключить отложенную загрузку в конструкторе контекста.

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