2014-08-20 3 views
3

Получение одного товара из таблицы, содержащей 6000 записей, занимает около 30 секунд. Очевидно, это неприемлемо, и я не могу понять, почему. Мой стек - это .NET 4.5, EF 6 и Web API 2. Является ли что-то невероятно неправильным с тем, что я сделал?Entity Framework действительно медленный Получение единственного элемента

// DbSet 
internal DbSet<TEntity> _dbSet; 

// Ctor 
public GenericRepository(TContext context) 
     { 
      _context = context; 
      _context.Configuration.ProxyCreationEnabled = false; 
      _dbSet = _context.Set<TEntity>(); 
     } 

// Really slow method 
public TEntity GetByFilter(Func<TEntity,bool> filter, params Expression<Func<TEntity, object>>[] includes) 
     { 
      IQueryable<TEntity> query = _dbSet; 
      if (includes != null) 
      { 
       foreach (var include in includes) 
        query = query.Include(include); 
      } 

      var entity = query.Where(filter).FirstOrDefault(); 

      return entity; 
     } 

// Here's how it's called. It returns a single item 
var x = _unitOfWork.Repository.GetByFilter(i => i.WinId == id, null); 
+0

Каковы ваши фильтр положения, как? –

+0

@ChristianSauer ... Я обновил свой вопрос –

+0

Вы выполнили трассировку SQL, чтобы определить, какой SQL был отправлен на сервер базы данных? Это может быть плохая индексация. Если вы можете зафиксировать точный SQL, отправленный в базу данных, и запустить его за пределы EF, он проявляет такую ​​же медленность? – barrypicker

ответ

7

Причина, почему это происходит медленно в использовании LINQ-к-объекты в пункте Where, то есть, необходимо выполнить предикат на клиента (C#) вместо сервера (SQL), то C# получает 6000 записей базы данных и затем фильтрует их в памяти.

Вы можете видеть это, потому что ваш параметр filter имеет тип Func, что подразумевает, что вы используете linq-to-objects посредством расширения IEnumerable.Where.

Вместо этого вы хотите использовать расширение IQueryable.Where, которое принимает параметр типа Expression. Это использует провайдер запросов Entity Framework и вместо этого использует linq-to-ef.

Update ваш метод подписи будет следующим:

public TEntity GetByFilter(
    Expression<Func<TEntity,bool>> filter, 
    params Expression<Func<TEntity, object>>[] includes) 

Это проиллюстрировано в следующем StackOverflow ответ https://stackoverflow.com/a/793584/507793

+0

Отличный ответ, я бы никогда не получил его. –

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