C# 用Linq选择top1

C# 用Linq选择top1,c#,sql-server,asp.net-mvc,linq,unit-of-work,C#,Sql Server,Asp.net Mvc,Linq,Unit Of Work,事实上,我正在与Linq和UOW(工作单元)合作,我正在与Linq一起轻松访问bbdd。我知道如果我想得到一个表的第一行,我可以这样做: int test4 = (from p in uow.ProductR.context.product where p.Id == 1715 select p.Id).FirstOrDefault(); 将在SQL Server中执行此操作的: SELECT TOP (1) [Extent1]

事实上,我正在与Linq和UOW(工作单元)合作,我正在与Linq一起轻松访问bbdd。我知道如果我想得到一个表的第一行,我可以这样做:

int test4 = (from p 
             in uow.ProductR.context.product 
             where p.Id == 1715 select p.Id).FirstOrDefault();
将在SQL Server中执行此操作的:

SELECT TOP (1) 
    [Extent1].[Id] AS [Id]
    FROM [dbo].[product] AS [Extent1]
    WHERE 1715 = [Extent1].[Id]
我的问题是,我可以用LINQ对UOW的通用存储库进行同样的操作吗?我是说,当我执行

int test2 = uow.ProductR.Get(p => p.Id == 1715).Select(p => p.Id).FirstOrDefault();

在SQL Server中,我得到:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
FROM [dbo].[product] AS [Extent1]
WHERE 1715 = [Extent1].[Id]
当然,使用第二种方法,当数据库有500k行时,速度会很慢。(我有更多的专栏,而不仅仅是2篇)

编辑:下面是带有GET声明的类

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{

    internal contextEntities context;
    internal DbSet<TEntity> dbSet;

    public GenericRepository(contextEntities context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = this.dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).AsQueryable();
        }
        else
        {
            return query.AsQueryable();
        }
    }
}
公共类GenericRepository:IGenericRepository其中tenty:class
{
内部语境;
内部数据库集;
公共通用存储库(上下文上下文)
{
this.context=上下文;
this.dbSet=context.Set();
}
公共虚拟IEnumerable Get(
表达式筛选器=空,
Func orderBy=null,
字符串includeProperties=“”)
{
IQueryable query=this.dbSet;
if(过滤器!=null)
{
query=query.Where(过滤器);
}
foreach(includeProperty.Split中的var includeProperty(新字符[]{',},StringSplitOptions.RemoveEmptyEntries))
{
query=query.Include(includeProperty);
}
if(orderBy!=null)
{
return orderBy(query.AsQueryable();
}
其他的
{
返回query.AsQueryable();
}
}
}

我希望我已经解释清楚了。

Get
需要返回一个
IQueryable
,而不是像现在这样返回一个
IEnumerable
。然后,
Get
的参数也变得无用,因为调用者只能执行
Get()。其中(…)
。API表面变得更干净,因为您可以删除参数


但您正在失去对数据库查询方式的控制。我假设您正在做一个用于测试目的的存储库(如果不是,那么拥有一个存储库可能是一个错误的选择)。测试以这种方式执行的查询变得更加困难。

Get
需要返回一个
IQueryable
,而不是像现在这样返回一个
IEnumerable
。然后,
Get
的参数也变得无用,因为调用者只能执行
Get()。其中(…)
。API表面变得更干净,因为您可以删除参数


但您正在失去对数据库查询方式的控制。我假设您正在做一个用于测试目的的存储库(如果不是,那么拥有一个存储库可能是一个错误的选择)。测试以这种方式执行的查询变得更加困难。

返回IQueryable将给您带来更大的灵活性,但它也暴露了随意修改存储库中定义的查询的可能性。如果您想为使用您的存储库返回前N行的用户提供一种标准机制,您可以添加一些额外的可选属性(注意,如果您还想允许通过存储库进行分页,而不需要创建单独的机制或公开基础IQueryable,Take与Skip是一种有用的机制)

您可以将Get方法签名更改为以下内容:

public virtual IEnumerable<TEntity> Get(
    Expression<Func<TEntity, bool>> filter = null,
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
    string includeProperties = "", int? maxResults = null)

请注意,不需要调用AsQueryable(),因为IOrderedQueryable和IQueryable都实现了IEnumerable。相反,调用ToList()以具体化结果集,使其得以执行。

返回IQueryable将给您带来更大的灵活性,但它也暴露了随意修改存储库中定义的查询的可能性。如果您想为使用您的存储库返回前N行的用户提供一种标准机制,您可以添加一些额外的可选属性(注意,如果您还想允许通过存储库进行分页,而不需要创建单独的机制或公开基础IQueryable,Take与Skip是一种有用的机制)

您可以将Get方法签名更改为以下内容:

public virtual IEnumerable<TEntity> Get(
    Expression<Func<TEntity, bool>> filter = null,
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
    string includeProperties = "", int? maxResults = null)

请注意,不需要调用AsQueryable(),因为IOrderedQueryable和IQueryable都实现了IEnumerable。相反,调用ToList()以具体化结果集,使其执行。

如何实现方法
Get
?此语句
uow.ProductR.Get(p=>p.Id==1715)
应使用
选择TOP 1
方法
如何实现?此语句
uow.ProductR.Get(p=>p.Id==1715)应该使用
选择前1名
,这就是问题所在。我没见过那该死的数字。上面的代码是测试代码,但目前我有几个正确实现UOW模式的项目,这些项目运行良好,有50到400人同时在线。(有5层的项目,前面、后面、应用程序、dal…)我不明白你为什么说这可能不是一个正确的选择。我需要阅读并告诉我一些事情?谢谢,如果有更多的信息,我可以回答得更好。为什么要添加存储库(而不是直接使用EF)?我有一个由UOW管理的EF。因此,当我需要来自前端的数据时,我访问Dal,在那里我在UOW上进行LINQ查询。这就是我现在介绍的简化流程示例。为什么要使用存储库?EF已经是一个存储库并且实现了UOW。我想当我开始使用它的时候,我对它们的了解还不够。可能会在新项目和EF6 MVC5中使用,这就是问题所在。我没见过那该死的数字。上面的代码是测试代码,但目前我有几个正确实现UOW模式的项目,这些项目运行良好,有50到400人同时在线。(项目有5层,前面,后面,应用程序,dal…)我不明白你为什么说
    if (orderBy != null)
    {
        return maxResults.HasValue() ? orderBy(query).Take((int)maxResults).ToList() : orderBy(query).ToList();
    }
    else
    {
        return maxResults.HasValue() ? query.take((int)maxResults).ToList() : query.ToList();
    }