Select 使用 Linq 排名第一
Select top1 with Linq
实际上我正在使用 Linq 和 UOW(工作单元),并且我正在使用 linq 轻松访问 bbdd。我知道如果我想得到一个 table 的第一行,我可以这样做:
int test4 = (from p
in uow.ProductR.context.product
where p.Id == 1715 select p.Id).FirstOrDefault();
这将在 SQL 服务器中执行:
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 服务器中我得到:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
FROM [dbo].[product] AS [Extent1]
WHERE 1715 = [Extent1].[Id]
当然,第二种方式,当数据库有500k行时,会很慢。 (我的栏目比较多,不止2个)
已编辑:这是带有 GET 声明的 Class
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
需要 return 一个 IQueryable
,而不是像现在这样 IEnumerable
。然后,Get
的参数也变得无用,因为调用者可以只做 Get().Where(...)
。 API 表面变得更干净,因为您可以删除参数。
但是您正在失去对数据库查询方式的控制。我假设你正在做一个用于测试目的的存储库(如果不是,那么拥有一个可能是一个糟糕的选择)。测试以这种方式执行的查询变得更加困难。
返回 IQueryable 将为您提供更大的灵活性,但它也暴露了随意修改您在存储库中定义的查询的可能性。如果您想为使用您的存储库的人提供一种标准机制 return 前 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() 以具体化结果集以便执行。
实际上我正在使用 Linq 和 UOW(工作单元),并且我正在使用 linq 轻松访问 bbdd。我知道如果我想得到一个 table 的第一行,我可以这样做:
int test4 = (from p
in uow.ProductR.context.product
where p.Id == 1715 select p.Id).FirstOrDefault();
这将在 SQL 服务器中执行:
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 服务器中我得到:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
FROM [dbo].[product] AS [Extent1]
WHERE 1715 = [Extent1].[Id]
当然,第二种方式,当数据库有500k行时,会很慢。 (我的栏目比较多,不止2个)
已编辑:这是带有 GET 声明的 Class
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
需要 return 一个 IQueryable
,而不是像现在这样 IEnumerable
。然后,Get
的参数也变得无用,因为调用者可以只做 Get().Where(...)
。 API 表面变得更干净,因为您可以删除参数。
但是您正在失去对数据库查询方式的控制。我假设你正在做一个用于测试目的的存储库(如果不是,那么拥有一个可能是一个糟糕的选择)。测试以这种方式执行的查询变得更加困难。
返回 IQueryable 将为您提供更大的灵活性,但它也暴露了随意修改您在存储库中定义的查询的可能性。如果您想为使用您的存储库的人提供一种标准机制 return 前 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() 以具体化结果集以便执行。