IQueryable 的总和列表
Sum List of IQueryable
给定一个 IQueryable 列表,如何在不在数据库中执行多个语句的情况下对每个 IQueryable 的计数求和?
return queries
.Sum(qy=> qy.Count());
以上有效,但每次查询都会访问数据库。
如果您使用的是 Entity Framework,则可以使用名为 EntityFramework.Extended 的扩展程序。有一个名为 Future Queries
的内置扩展。这将允许您指定在下次访问数据库时执行查询。
NuGet 命令:
Install-Package EntityFramework.Extended
示例代码:
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
var modelSet1 = context.Models.Where(x => x.ModelId < 25).FutureCount();
var modelSet2 = context.Models.Where(x => x.ModelId > 25 && x.ModelId < 32).FutureCount();
var modelSet3 = context.Models.Where(x => x.ModelId > 32).FutureCount();
var queries = new [] {modelSet1, modelSet2, modelSet3};
var countQueries = queries.Sum(x => x.Value);
Console.WriteLine(countQueries);
}
Console.ReadLine();
}
从这个想法出发Sum(q1,q2) = q1.Concat(q2).Count()
我测试了以下扩展:
public static class LinqExtensions
{
public static IQueryable<object> ConcatAny<T,R>(this IQueryable<T> q1, IQueryable<R> q2)
{
return q1.Select(c=>(object)null).Concat(q2.Select(c=>(object)null));
}
public static IQueryable<object> ConcatAll(this IEnumerable<IQueryable<object>> queries)
{
var resultQuery = queries.First();
foreach (var query in queries.Skip(1))
{
resultQuery = resultQuery.ConcatAny(query);
}
return resultQuery;
}
}
我假设您有 IQueryable<T>
、IQueryable<R>
等异构查询,并且您有兴趣计算所有行,无论来源是什么。
因此您可以使用这些扩展,例如
var q1 = Table1.AsQueryable();
var q2 = Table2.AsQueryable();
var q3 = Table3.AsQueryable();
var queries = new IQueryable<object>[] {q1,q2,q3}; // we use here the covariance feature
return queries.ConcatAll().Count();
生成的 SQL 可能看起来像这样
SELECT COUNT(*) AS [value]
FROM (
SELECT NULL AS [EMPTY]
FROM (
SELECT NULL AS [EMPTY]
FROM [Table1] AS [t0]
UNION ALL
SELECT NULL AS [EMPTY]
FROM [Table2] AS [t1]
) AS [t2]
UNION ALL
SELECT NULL AS [EMPTY]
FROM [Table3] AS [t3]
) AS [t4]
虽然我认为不是很有效
好的,晚了几分钟,但我明白了!
这是代码:
public static class LinqExtensions
{
public static int CountAll(this IEnumerable<IQueryable<object>> queries)
{
if (queries == null || !queries.Any())
{
throw new ArgumentException("Queries parameter cannot be null or empty");
}
Expression ex = Expression.Constant(0);
foreach (var qy in queries)
{
// create count expression
var expression = Expression.Call(
typeof(Queryable),
"Count",
new[] { qy.ElementType },
qy.Expression
);
ex = Expression.Add(ex, expression);
}
return queries.First().Provider.Execute<int>(ex);
}
}
您将其用作 queries.CountAll()
,其中查询是 Adrian 的回答中的 IEnumerable<IQueryable<object>>
,甚至是简单的 IEnumerable<IQueryable>
。
这是分析器的 SQL 结果示例:
exec sp_executesql N'SELECT @p0 + ((
SELECT COUNT(*)
FROM [A] AS [t0]
WHERE [t0].[i1] >= @p1
)) + ((
SELECT COUNT(*)
FROM [B] AS [t1]
WHERE [t1].[i2] >= @p2
)) + ((
SELECT COUNT(*)
FROM [C] AS [t2]
WHERE [t2].[i3] >= @p3
)) AS [value]',N'@p0 int,@p1 int,@p2 int,@p3 int',@p0=0,@p1=2,@p2=2,@p3=2
代表
var a = db.GetTable<A>();
var b = db.GetTable<B>();
var c = db.GetTable<C>();
var q1 = a.Where(v => v.i1 >= 2);
var q2 = b.Where(v => v.i2 >= 2);
var q3 = c.Where(v => v.i3 >= 2);
var queries = new IQueryable<object>[] {
q1,q2,q3
};
请注意,A、B 和 C 是不同的 objects/tables,具有不同数量的 properties/columns,并且表达式是随机的 Where 过滤器。
您可以先使用 Aggregate
函数和 Concat
组合 IQueryable,然后 Count
合计,如下所示:
return queries.Aggregate((x,y) => x.Concat(y)).Count()
给定一个 IQueryable 列表,如何在不在数据库中执行多个语句的情况下对每个 IQueryable 的计数求和?
return queries
.Sum(qy=> qy.Count());
以上有效,但每次查询都会访问数据库。
如果您使用的是 Entity Framework,则可以使用名为 EntityFramework.Extended 的扩展程序。有一个名为 Future Queries
的内置扩展。这将允许您指定在下次访问数据库时执行查询。
NuGet 命令:
Install-Package EntityFramework.Extended
示例代码:
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
var modelSet1 = context.Models.Where(x => x.ModelId < 25).FutureCount();
var modelSet2 = context.Models.Where(x => x.ModelId > 25 && x.ModelId < 32).FutureCount();
var modelSet3 = context.Models.Where(x => x.ModelId > 32).FutureCount();
var queries = new [] {modelSet1, modelSet2, modelSet3};
var countQueries = queries.Sum(x => x.Value);
Console.WriteLine(countQueries);
}
Console.ReadLine();
}
从这个想法出发Sum(q1,q2) = q1.Concat(q2).Count()
我测试了以下扩展:
public static class LinqExtensions
{
public static IQueryable<object> ConcatAny<T,R>(this IQueryable<T> q1, IQueryable<R> q2)
{
return q1.Select(c=>(object)null).Concat(q2.Select(c=>(object)null));
}
public static IQueryable<object> ConcatAll(this IEnumerable<IQueryable<object>> queries)
{
var resultQuery = queries.First();
foreach (var query in queries.Skip(1))
{
resultQuery = resultQuery.ConcatAny(query);
}
return resultQuery;
}
}
我假设您有 IQueryable<T>
、IQueryable<R>
等异构查询,并且您有兴趣计算所有行,无论来源是什么。
因此您可以使用这些扩展,例如
var q1 = Table1.AsQueryable();
var q2 = Table2.AsQueryable();
var q3 = Table3.AsQueryable();
var queries = new IQueryable<object>[] {q1,q2,q3}; // we use here the covariance feature
return queries.ConcatAll().Count();
生成的 SQL 可能看起来像这样
SELECT COUNT(*) AS [value]
FROM (
SELECT NULL AS [EMPTY]
FROM (
SELECT NULL AS [EMPTY]
FROM [Table1] AS [t0]
UNION ALL
SELECT NULL AS [EMPTY]
FROM [Table2] AS [t1]
) AS [t2]
UNION ALL
SELECT NULL AS [EMPTY]
FROM [Table3] AS [t3]
) AS [t4]
虽然我认为不是很有效
好的,晚了几分钟,但我明白了! 这是代码:
public static class LinqExtensions
{
public static int CountAll(this IEnumerable<IQueryable<object>> queries)
{
if (queries == null || !queries.Any())
{
throw new ArgumentException("Queries parameter cannot be null or empty");
}
Expression ex = Expression.Constant(0);
foreach (var qy in queries)
{
// create count expression
var expression = Expression.Call(
typeof(Queryable),
"Count",
new[] { qy.ElementType },
qy.Expression
);
ex = Expression.Add(ex, expression);
}
return queries.First().Provider.Execute<int>(ex);
}
}
您将其用作 queries.CountAll()
,其中查询是 Adrian 的回答中的 IEnumerable<IQueryable<object>>
,甚至是简单的 IEnumerable<IQueryable>
。
这是分析器的 SQL 结果示例:
exec sp_executesql N'SELECT @p0 + ((
SELECT COUNT(*)
FROM [A] AS [t0]
WHERE [t0].[i1] >= @p1
)) + ((
SELECT COUNT(*)
FROM [B] AS [t1]
WHERE [t1].[i2] >= @p2
)) + ((
SELECT COUNT(*)
FROM [C] AS [t2]
WHERE [t2].[i3] >= @p3
)) AS [value]',N'@p0 int,@p1 int,@p2 int,@p3 int',@p0=0,@p1=2,@p2=2,@p3=2
代表
var a = db.GetTable<A>();
var b = db.GetTable<B>();
var c = db.GetTable<C>();
var q1 = a.Where(v => v.i1 >= 2);
var q2 = b.Where(v => v.i2 >= 2);
var q3 = c.Where(v => v.i3 >= 2);
var queries = new IQueryable<object>[] {
q1,q2,q3
};
请注意,A、B 和 C 是不同的 objects/tables,具有不同数量的 properties/columns,并且表达式是随机的 Where 过滤器。
您可以先使用 Aggregate
函数和 Concat
组合 IQueryable,然后 Count
合计,如下所示:
return queries.Aggregate((x,y) => x.Concat(y)).Count()