C# Linq性能介于

C# Linq性能介于,c#,.net,entity-framework,linq,C#,.net,Entity Framework,Linq,我正在使用实体框架,我想知道以下代码之间是否有任何差异。第一个和第二个代码似乎获取了Entidad.Nombre==“Empresa”筛选的所有项目,最后一个代码似乎只获取Entidad.Nombre==“Empresa”筛选的项目。我错了吗?什么更好 var listFields = from b in unitOfWork.PropiedadRepository.Get() where b.Entidad.Nombre == "Empresa

我正在使用实体框架,我想知道以下代码之间是否有任何差异。第一个和第二个代码似乎获取了Entidad.Nombre==“Empresa”筛选的所有项目,最后一个代码似乎只获取Entidad.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;
    }
}
公共密封类通用存储,其中tenty:class
{
私有只读配置DBDataContext\u上下文;
私有只读数据库集_DbSet;
公共GenericRepository(ConfigurationDbDataContext上下文)
{
_上下文=上下文;
_dbSet=context.Set();
}
公共数字获取(
表达式筛选器=空,
Func orderBy=null,
字符串includeProperties=“”)
{
IQueryable查询=_dbSet;
if(过滤器!=null)
{
query=query.Where(过滤器);
}
query=includeProperty.Split(新[]{',},StringSplitOptions.RemoveEmptyEntries).聚合(query,(current,includeProperty)=>current.Include(includeProperty));
//ReSharper禁用一次ConvertifStatementToReturn语句
if(orderBy!=null)
{
returnorderby(query.ToList();
}
其他的
{
返回query.ToList();
}
}
公共TEntity GetById(对象id)
{
返回_dbSet.Find(id);
}
公共无效插入(TEntity实体)
{
_添加(实体);
}
公共无效删除(对象id)
{
var entityToDelete=_dbSet.Find(id);
删除(entityToDelete);
}
公共作废删除(TEntity entityToDelete)
{
if(_context.Entry(entityToDelete.State==EntityState.Detached)
{
_数据库集连接(entityToDelete);
}
_dbSet.Remove(entityToDelete);
}
公共无效更新(TEntity entityToUpdate)
{
_数据库集附加(实体更新);
_context.Entry(entityToUpdate.State=EntityState.Modified;
}
}
你说得对

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

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

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

通常,人们更喜欢让服务器过滤,以便linq to entities,但这实际上取决于一些参数和目标

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

另外,正如Kaspars所提醒的,尾随空格的处理是不同的

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而不是IEnumberable。如果返回IQueryable,则在需要具体化结果集之前,不会执行该语句。如果Get()返回IQueryable而不是调用ToList(),那么这两条语句将执行相同的语句。

正如其他人所说的,第三条查询将是最快的,因为过滤是在DB级别完成的。仅将相关记录转移给客户

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

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

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

public IQueryable<TEntity> GetAll()
{
    return _dbSet
        .Where(x => !x.IsDeleted)
        .OrderBy(x => x.Date);
}
public IQueryable GetAll()
{
返回数据集
.其中(x=>!x.IsDeleted)
.OrderBy(x=>x.Date);
}

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

通常最好在数据库端进行过滤,以避免返回数据的开销,因此最后一个选项似乎是最好的。不仅如此。如果您使用的是SQL server,另一个有趣的区别是尾随空格的处理方式。在Linq to Entities
dbSet.Where(x=>x.Name==“test”)
dbSet.Where(x=>x.Name==“test”)
将给出相同的结果,因为SQL server忽略尾随空格,但Linq to对象的结果将给出不同的结果,因为尾随空格不会被忽略。