C# 实体框架repostory模式GetAll()太慢

C# 实体框架repostory模式GetAll()太慢,c#,asp.net-mvc,linq,entity-framework-6,C#,Asp.net Mvc,Linq,Entity Framework 6,我正在使用存储库层。这里我的问题是GetAll()方法在连接具有大记录的表时太慢。运行一个简单的查询需要40秒 IGenericRepository: public interface IGenericRepository<TEntity> { TEntity FindBy(Expression<Func<TEntity, bool>> predicate); IEnumerable<TEntity> GetAll(); T

我正在使用存储库层。这里我的问题是GetAll()方法在连接具有大记录的表时太慢。运行一个简单的查询需要40秒

IGenericRepository:

public interface IGenericRepository<TEntity>
{
    TEntity FindBy(Expression<Func<TEntity, bool>> predicate);
    IEnumerable<TEntity> GetAll();
    TEntity GetById(int id);
    TEntity Insert(TEntity entity);
    TEntity Update(TEntity entity);
    void Delete(object id);
    void Save();
}
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    private MyStoreContext _dbContext;
    protected DbSet<TEntity> DbSet;

    public GenericRepository()
    {
        _dbContext = new MyStoreContext ();
        DbSet = _dbContext.Set<TEntity>();
    }

    public TEntity FindBy(Expression<Func<TEntity, bool>> predicate)
    {
        return DbSet.Where(predicate).SingleOrDefault();
    }

    public IEnumerable<TEntity> GetAll()
    {
        return DbSet.AsNoTracking();
    }

    public TEntity GetById(int id)
    {
        return DbSet.Find(id);
    }

    public TEntity Insert(TEntity entity)
    {
        DbSet.Add(entity);
        Save();
        return entity;
    }

    public TEntity Update(TEntity obj)
    {
        DbSet.Attach(obj);
        _dbContext.Entry(obj).State = EntityState.Modified;

        Save();
        return obj;
    }

    public void Delete(object id)
    {
        TEntity entityToDelete = DbSet.Find(id);
        Delete(entityToDelete);
    }

    public void Delete(TEntity entityToDelete)
    {
        if (_dbContext.Entry(entityToDelete).State == EntityState.Detached)
        {
            DbSet.Attach(entityToDelete);
        }

        DbSet.Remove(entityToDelete);
        Save();
    }

    public void Save()
    {
        try
        {
            _dbContext.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    System.Console.WriteLine("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); // you just put the log to know the errors
                }
            }
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_dbContext != null)
            {
                _dbContext.Dispose();
                _dbContext = null;
            }
        }
    }
}
查询返回10条记录。ParfactFreposition包含992590行,Invereposition包含41908行


我做错了什么?

这是因为您混合和匹配了基于存储库的查询和LINQ查询。与其进行真正的联接,不如获取每个表的所有行,然后在内存中联接它们

解决此问题的最简单方法可能是从
GetAll
方法返回
IQueryable
,而不是
IEnumerable
。使用
IEnumerable
强制查询求值。如果要返回
IEnumerable
,则应完全烘焙数据,即不需要对查询进行进一步修改(包括联接)

也就是说,这是尝试将存储库模式与EF一起使用的又一个失败。如果你不十分小心,你最终会引入这样的逻辑错误,这些错误的发生原因并不明显。实体框架已经实现了存储库模式;这就是
DbSet
的含义。如果您想在上面进行抽象,请引入服务层。这样,您就可以简单地使用如下方法:

public IEnumerable<MyViewModel> GetConceptosDetalle()
{
    ...
}
public IEnumerable GetConceptosDetalle()
{
...
}
该方法将包含整个查询(直接使用EF,而不是完全不必要的存储库层)。这样,应用程序只需调用一个返回所需数据的方法,服务层包含所有逻辑。这才是真正的抽象。有了存储库,您的代码库中就到处都是逻辑


注意:为了便于解释,我让它返回
MyViewModel
,但实际上,您应该返回某种DTO,然后可以将其映射到视图模型。将视图业务逻辑泄漏到服务层是个坏主意。

我认为这将下载这两个表的全部内容,并将它们连接到内存中,而不是数据库中,因为
GetAll
IEnumerable
。非常感谢您的建议。现在我正在努力+1反对将实体框架包装在存储库/工作单元模式中的做法非常困难,因为这是一个小问题。本周到目前为止,我已经两次努力地进行这场对话。@BradleyUffner:我不需要投票。没有充分的理由将存储库模式与EF或任何ORM周期一起使用。存储库模式解决的问题是由ORM解决的,这就是为什么我所见过的几乎所有ORM都实现了存储库模式。如果你的目标是抽象EF,那么还有更合适的方法,比如前面提到的服务层。对,我只是想表达我对这一点的同意,因为我觉得我需要每周向工作中的人们解释同样的事情。@Rolando:好吧,不是自我推销,但有一点:和。我不知道其他人写的任何东西,但我相信一个简单的谷歌搜索可以浮出水面。
public IEnumerable<MyViewModel> GetConceptosDetalle()
{
    ...
}