所以我试图运行一个类似于SQL查询的Linq查询:
SELECT COUNT(*)
FROM table
WHERE ww >= [wwStartSelected]
AND ww <= [wwEndSelected]
AND manager='[managerName]'
AND status='Done'
GROUP BY ww;
获取给定ww范围内的行数(任务)的计数,这些行(任务)在特定管理器下标记为已完成并按ww分组。我试图创建一个返回类似的LINQ查询(wwStartSelected&amp;&amp; wwEndSelected是全局变量):
protected List<int> getManagerDoneCount(string managerName)
{
using (var context = new InfoDBContext())
{
List<int> managerDoneCount = context.InfoSet.Where(x => x.ww >= wwStartSelected && x.ww <= wwEndSelected && x.manager == managerName && x.status == "Done").GroupBy(x => x.ww).Count().ToList();
return managerDoneCount;
}
}
此查询将输入图表:
var testChart = new Chart(width: 600, height: 400)
.AddTitle("Test")
.AddSeries(
name: "Done",
chartType: "StackedColumn100",
xValue: new[] { WWList },
yValues: new[] { getManagerDoneCount("someManager") })
然而,我遇到了Linq系列的问题,并说:
'int'不包含'ToList'的定义,也没有扩展方法'ToList' 接受第一个'int'类型的参数可以找到(是吗? 缺少using指令或程序集引用?)
有没有办法轻松解决这个问题,或者我必须转换为字符串,然后转换回int为图表系列(后者似乎有点傻[但如果是这样,最好的方法这样做]) ?
答案 0 :(得分:6)
.Count().ToList()
您要求它计算列表中的项目(这会产生一个数字),然后将该单个数字转换为列表,这没有任何意义。
返回列表并稍后计算(省略.Count()
)或更改方法以返回int
而不是List<int>
并省略.ToList()
protected int getManagerDoneCount(string managerName)
{
using (var context = new InfoDBContext())
{
int managerDoneCount = context.InfoSet
.Where(x => x.ww >= wwStartSelected &&
x.ww <= wwEndSelected &&
x.manager == managerName &&
x.status == "Done")
.GroupBy(x => x.ww)
.Count();
return managerDoneCount;
}
}
顺便说一句,为了节省您编写数百种这些方法的风险,您可以将Where
子句作为参数传递...
using System.Linq.Expressions;
protected int getManagerCount(string managerName, Expression<Info> predicate)
{
using (var context = new InfoDBContext())
{
int managerDoneCount = context.InfoSet
.Where(predicate)
.GroupBy(x => x.ww)
.Count();
return managerDoneCount;
}
}
然后这样称呼它......
var count = getManagerCount("...", x => x.ww >= wwStartSelected &&
x.ww <= wwEndSelected &&
x.manager == managerName &&
x.status == "Done");
要返回每个组的计数,List<int>
是一个坏主意,因为您没有对这些组进行排序,因此计数将以未定义的顺序排列。理想的解决方案是拥有一个具有适当Key
和Count
属性的类,但为了简化示例,我将使用一个元组。
//I'm assuming `ww` is an `int`, change the first type parameter of the tuple as appropriate
List<Tuple<int, int>> counts = context.InfoSet
.Where(x => x.ww >= wwStartSelected &&
x.ww <= wwEndSelected &&
x.manager == managerName &&
x.status == "Done")
.GroupBy(x => x.ww)
.Select(x => new Tuple<int, int>(x.Key, x.Count())).ToList();
请注意,在您完成论坛后,下一个Select
针对的是该群组,该群组对您所分组的内容具有Key
属性计算,求和等的聚合方法。
如果确实只想要一个整数列表,请将最后一个选择更改为...
.Select(x => x.Count())
如果您没有将其传递出该方法,我只会使用一个匿名类...
.Select(x => new {Ww = x.Key, Count = x.Count()})
但是在方法签名中没有用。如果您使用CountResult
和Ww
属性创建了Count
课程<...
.Select(x => new CountResult{Ww = x.Key, Count = x.Count()})
Linq-To-Entities构建一个针对SQL Server执行的表达式树,而Linq-To-Objects在客户端上运行内存并具有更多功能(因为它不需要计算出等效的SQL )。在这种情况下,当它从SQL获得结果时,它会创建一个特殊的代理类,其外观/行为与您的实体相同,但处理其他内容,例如跟踪哪些属性已更改。因此,您只能使用可以构造的类(使用无参数构造函数),然后然后设置(并跟踪)其属性。
(虽然你没有指定Linq-To-Entities,但从你的问题中可以明显看出来,所以我应该抓住这个)。
LINQ不会处理列表,但是IQueryable
s,它们支持延迟评估。
例如,如果你......
var a = dbcontext.SomeSet.Where(x => true); //You could omit the Where entirely, just for illustration purposes
var b = a.Where(x => x.Id < 100);
var c = b.ToList();
查询仅在最后一行执行,数据库最多返回100条记录。 a
和b
都是IQueryable<SomeSet>
和&#34;只是&#34;包含表达式树(基本上是表示到目前为止应用的约束/操作的层次结构)。
因此,为了能够使用参数化构造函数/其他Linq-To-Object特性,我们可以强制进行评估......
List<Tuple<int, int>> counts = context.InfoSet
.Where(x => x.ww >= wwStartSelected &&
x.ww <= wwEndSelected &&
x.manager == managerName &&
x.status == "Done")
.GroupBy(x => x.ww)
.ToList() // <<<< Force execution of SQL query
.Select(x => new Tuple<int, int>(x.Key, x.Count())).ToList();
如果您愿意,应该允许您使用构造函数。
也就是说,获得零计数很困难 - 就像从数据库中获取计数一样(如果按字段分组,它不会显示任何0
计数)。有很多方法可以解决这个问题,您使用哪种方法取决于您使用的数据量。所有这些都需要一些方式来定义所有可能的值。我将使用List<string>
,因为它与LINQ
例如,您可以获取所有值的列表,并为每个值运行不同的计数。这很简单,但需要多次查询。如果有很多团体,那可能很贵......
var groups = new List<string> {"ww1", "ww2", ...};
var counts = groups.Select(g => context.InfoSet.Where(x => x.ww == g &&
x.manager == managerName &&
x.status == "Done").Count());
(这只会返回计数,但与您的组列表的顺序相同。如前所述,您可以Select
任何您喜欢的内容,包括CountResult ...)
var counts = groups.Select(g => new CountResult {
Ww = g,
Count = context.InfoSet.Where(x => x.ww == g &&
x.manager == managerName &&
x.status == "Done").Count();
});
或者,您可以运行先前执行的查询,并添加计数为0
的缺失组。这样做的好处是可以运行单个SQL查询并让数据库完成所有繁重工作(好吧,处理一些计数并不太昂贵,但是其他问题值得记住 - 你不要&# 39; t想要将整个数据库表存入内存并在那里进行处理!)。
var groups = new List<string> {"ww1", "ww2", ...};
var previousQuery = ... //(I'll assume a List<CountResult> but tuple would work the same)
var finalList = previousQuery.Concat(
groups.Where(g => ! previousQuery.Exists(p => p.Ww == g))
.Select(g => new CountResult {Ww=g, Count=0})
);
简而言之,取以前的结果集,并将其与结果连接(连接); (获取所有组的列表,删除已在第1组中的组,其余部分创建一个具有相应ww
且计数为0
的新对象)