【问题标题】:Select top1 with Linq使用 Linq 选择 top1
【发布时间】:2015-11-27 20:59:38
【问题描述】:

实际上,我正在使用 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();

或者

var test3 = uow.ProductR.Get(p => p.Id == 1715).Select(p => new { p.Id });

在 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();
        }
    }
}

希望我已经解释清楚了。

【问题讨论】:

  • 方法Get是如何实现的?这个声明uow.ProductR.Get(p =&gt; p.Id == 1715).Select(p =&gt; p.Id).FirstOrDefault();应该使用SELECT TOP 1

标签: c# sql-server asp.net-mvc linq unit-of-work


【解决方案1】:

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

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

【讨论】:

  • 这就是问题所在。我没见过那个该死的IEnumerable。上面的代码是测试,但目前我有几个正确实现了 UOW 模式的项目,并且这些项目运行良好,同时在线人数在 50 到 400 人之间的项目。 (有 5 层的项目,正面、背面、应用程序、dal ...)我不明白你为什么说这可能不是一个正确的选择。我需要阅读并告知我一些事情吗?谢谢
  • 我可以通过更多信息更好地回答。为什么要添加存储库(而不是直接使用 EF)?
  • 我有由 UOW 管理的 EF。因此,当我需要来自前端的数据时,我会访问我在 UOW 上进行 LINQ 查询的 Dal。这就是我现在所拥有的流程的简化示例。
  • 为什么您使用存储库? EF 已经是一个存储库并实现了 UOW。
  • 我想当我开始使用它时,我对它们还不够了解。可能会在新项目和 EF6 MVC5 中取消它
【解决方案2】:

返回 IQueryable 将为您提供更大的灵活性,但它也暴露了随意修改您在存储库中定义的查询的可能性。如果您想为使用您的存储库的人提供返回前 N 行的标准机制,您可以添加一些额外的可选属性(请注意,如果您还想允许通过您的存储库,无需创建单独的机制或公开底层 IQueryable)。

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

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

然后在你的 Get 方法中(这应该被重构,但你明白了):

    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();
    }

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

【讨论】:

  • 是的,我明白你的意思,但我的主要问题不仅是获得 1 行,如果没有,在数据库中执行的查询不是我想在 LINQ 中运行的(所以它效率低下)。它返回的列比想要的多谢谢
猜你喜欢
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多