林克的表现介于之间

本文关键字:之间 于之间 林克 | 更新日期: 2023-09-27 18:14:18

我正在使用实体框架,我想知道以下代码之间是否有任何区别。第一个和第二个代码似乎得到了Entidad.Nombre="Empresa"过滤后的所有项目,最后一个代码似乎只得到了Entitad.Nombre=="Empresa"处的项目。我错了吗?什么更好?

var listFields = from b in unitOfWork.PropiedadRepository.Get()
                         where b.Entidad.Nombre == "Empresa"
                         select b;
var listFields2 = unitOfWork.PropiedadRepository.Get().Where(x => x.Entidad.Nombre == "Empresa");
var listFields3 = unitOfWork.PropiedadRepository.Get(x => x.Entidad.Nombre == "Empresa");

这是GenericRepository类。所有的存储库都继承了它。

public sealed class GenericRepository<TEntity> where TEntity : class
{
    private readonly ConfigurationDbDataContext _context;
    private readonly DbSet<TEntity> _dbSet;
    public GenericRepository(ConfigurationDbDataContext context)
    {
        _context = context;
        _dbSet = context.Set<TEntity>();
    }
    public IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = _dbSet;
        if (filter != null)
        {
            query = query.Where(filter);
        }
        query = includeProperties.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
        // ReSharper disable once ConvertIfStatementToReturnStatement
        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }
    public TEntity GetById(object id)
    {
        return _dbSet.Find(id);
    }
    public void Insert(TEntity entity)
    {
        _dbSet.Add(entity);
    }
    public void Delete(object id)
    {
        var entityToDelete = _dbSet.Find(id);
        Delete(entityToDelete);
    }
    public void Delete(TEntity entityToDelete)
    {
        if (_context.Entry(entityToDelete).State == EntityState.Detached)
        {
            _dbSet.Attach(entityToDelete);
        }
        _dbSet.Remove(entityToDelete);
    }
    public void Update(TEntity entityToUpdate)
    {
        _dbSet.Attach(entityToUpdate);
        _context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

林克的表现介于之间

你说得对。

在最后一种情况下,where子句的求值将提供给数据服务器(linq-to-entities(,客户端只接收过滤后的数据。

在其他情况下,客户端接收所有数据,然后对其进行筛选(linq to object(。

也就是说:我们谈论的是什么表演?CPU、网络、客户端、服务器端?

通常,人们更喜欢让服务器对实体进行筛选,但这实际上取决于一些参数和目标。

请注意,imho,linq-to-entities和linq-to-object之间最令人惊讶的区别:linq-to-object区分大小写。对于linq-to实体,它取决于数据库/表/列排序规则。

此外,正如Kaspars所提醒的,对尾随空白的处理是不同的。

正如其他人已经说过的,第三个查询将是最快的,因为过滤是在DB级别完成的。只有相关记录才会转移给客户。

虽然主要问题已经得到了回答,但我还是建议对基本存储库进行更改,使其更具弹性。目前,您将所有可能的筛选选项传递给存储库Get函数,并在那里应用它们。这似乎是非常有限和没有必要的。

如果在某个时刻您希望在DB级别执行额外的操作(例如,GroupBy(,则除非向Get函数添加额外的参数,否则将无法执行此操作。

我建议将Get函数改为GetAll,并返回IQueryable。您可以在那里添加默认的筛选和排序规则。

public IQueryable<TEntity> GetAll()
{
    return _dbSet
        .Where(x => !x.IsDeleted)
        .OrderBy(x => x.Date);
}

通过这样做,您的所有查询将始终在DB级别执行过滤/排序/聚合。此外,这将更具弹性,因为您可以使用Linq-to-Entities提供的所有功能。

var listFields3 = unitOfWork.PropiedadRepository
                            .Get(x => x.Entidad.Nombre == "Empresa");

最后一种情况更好。实体框架推迟SQL查询的执行,直到您以某种方式实现结果集。它查看整个表达式,然后在此基础上制定查询。

Get()方法中,您调用ToList(),它确实实现了结果集。因此,如果您调用.Get().Where(...),那么第一个Get()是在没有过滤器的情况下调用的,因为Get()调用ToList(),它将把所有数据拉回到内存中,然后根据它执行Where()

在最后一种情况中,在调用ToList()之前,在Get()方法中调用Where()。这意味着where子句将用于构造SQL查询,该查询过滤SQL Server上的数据,而不是应用程序服务器上的内存中的数据,并且效率会高得多。

这里需要考虑的是,您是否希望让存储库返回IQueryable<T>而不是IEnumerable<T>。如果返回IQueryable,那么在需要具体化结果集之前,不会执行该语句。如果Get()返回IQueryable而不是调用ToList(),那么两个语句将执行相同的语句。