c# - 'int'不包含'ToList'的定义

标签 c# asp.net-mvc linq asp.net-mvc-5

因此,我尝试运行类似于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和&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(后者似乎有点愚蠢[但如果是,那是最好的方法])?

最佳答案

.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>是个坏主意,因为您不对组进行排序,因此计数将处于不确定的顺序。理想的解决方案是使类具有适当的KeyCount属性,但是为了简化示例,我将使用元组。

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


但这在方法签名中没有用。如果您创建具有CountResultWw属性的Count类...

.Select(x => new CountResult{Ww = x.Key, Count = x.Count()})


编辑回复:评论#2

Linq-To-Entities构建一个表达式树,该树可针对SQL Server执行,而Linq-To-Objects在客户端的内存中运行并具有更多功能(因为它不需要计算出等效的SQL)。在这种情况下,当它从SQL获取结果时,它会创建一个特殊的代理类,该类看起来/行为与您的实体相同,但是会处理其他事情,例如跟踪哪些属性已更改。因此,您只能使用可以构造的类(使用无参数构造函数),然后设置(并跟踪)它们的属性。

(尽管您未指定Linq-To-Entities,但从您的问题中可以明显看出,所以我应该抓住了这一点)。

LINQ不处理列表,而是处理支持延迟评估的IQueryable

例如,如果您这样做...

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条记录。 ab均为IQueryable<SomeSet>,“ just”包含表达式树(基本上是表示到目前为止已应用的约束/操作的层次结构)。

因此,为了能够使用参数化的构造函数/其他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查询并让数据库完成所有繁重的工作(好吧,处理几个计数虽然不太昂贵,但是值得记住其他问题-您并不想获得全部信息DB表在内存中并在那里进行处理!)。

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的新对象)

关于c# - 'int'不包含'ToList'的定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33047950/

相关文章:

c# - 格式化导航栏颜色并在 Razor 中添加分隔线

asp.net-mvc - Windows Azure WebRole 陷入部署循环

c# - 推送到生产服务器时 ASP.NET MVC 错误 500

c# - Linq 检查 null 并按 orderby 替换 null 值

c# - 在 Linux 上反序列化 TimeZoneInfo 会抛出 `The Month parameter must be in the range 1 through 12`

c# - 路径中的 XML 非法字符

c# - 如何在多个 Controller 类之间重用 Action Method 验证

c# - ElasticSearch在多个字段上完全匹配

c# - IEnumerable<T> 包装器的 GetEnumerator() 的替代实现

c# - 尝试注销时,提供的防伪 token 是针对用户 "XXXX"的,但当前用户是 ""