【问题标题】:How to get a count of the items returned by a LINQ query如何获取 LINQ 查询返回的项目的计数
【发布时间】:2017-01-19 08:19:46
【问题描述】:

我正在尝试获取 LINQ 查询返回的项目的计数。我会假设它是 .Count 但显然不是。 我正在从 Excel 加载一个 DataTable,然后根据标识符获取不同的行。我现在正在尝试计算退回的物品数量。 Leases 包含我想要计数的行的数据。我尝试了一些事情(现在已注释掉)但没有成功。

也许 LINQ 专家可以帮助我?

这是我的代码:

Dim Leases As Object
Dim dtData As System.Data.DataTable = LoadExcelAsDb(oFile.FullName)
Try
    ' How many leases are there
    Leases = From row In dtData.AsEnumerable() Select row.Field(Of Object)("F2") Distinct
    '    LeaseCt = New System.Linq.SystemCore_EnumerableDebugView(Of Object)(Leases).Items.count 
    '    LeaseCt = New System.Linq.Enumerable(Of Object)(Leases).Items.count
    '    LeaseCt = Leases.Count
Catch ex As Exception
    Debug.WriteLine("Error reading files" + ex.ToString)
End Try

''' <summary>
''' Loads an excel file as a datatable
''' </summary>
''' <param name="sFilename">Filename of excel to be loaded </param>   
''' <returns>Populated Datatable</returns>
Private Function LoadExcelAsDb(sFilename As String) As System.Data.DataTable
    ' Connect to Excel get table
    Dim oConnection As System.Data.OleDb.OleDbConnection = New System.Data.OleDb.OleDbConnection("provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + sFilename + " ; Extended Properties=Excel 12.0;")
    Dim oCommand As System.Data.OleDb.OleDbDataAdapter = New System.Data.OleDb.OleDbDataAdapter("select * from [Sheet1$]", oConnection)

    Dim DtSet As System.Data.DataTable = New System.Data.DataTable
    Try
        oCommand.Fill(DtSet)
    Catch ex As Exception
        Debug.WriteLine("Error reading files" + ex.ToString)
    End Try

    Return DtSet
End Function

【问题讨论】:

  • Leases 将是一个“内存查询”——在你执行之前它不会有计数。 LeaseCt = (Leases).Count() 将为您提供 that 查询的计数
  • LeaseCt = Leases.ToList().Count()
  • 当我尝试 Leases.ToList().Count() 时,我收到一条错误消息,提示 Tolist 不可用
  • 当我尝试 LeaseCt = (Leases).Count() 时,我收到错误“未找到类型 'Integer' 的公共成员 'Count'。”

标签: vb.net linq


【解决方案1】:

使用 LINQ 时需要掌握的一个主要概念是被查询的对象必须是可枚举的。这意味着它至少实现了接口System.Collections.IEnumerable。最好被查询的对象实现System.Collections.Generic.IEnumerable(Of T)接口。

在您的 LINQ 语句中:

Leases = From row In dtData.AsEnumerable() Select row.Field(Of Object)("F2") Distinct

查询的对象是结果dtData.AsEnumerable()。 Datatable 扩展方法AsEnumerable 返回一个System.Data.EnnumerableRowCollection(Of System.Data.DataRow),因此语句中的row 变量是DataRow 类型。

语句选择 row.Field(Of Object)("F2")。由于这将返回 System.Object 类型的单个对象,因此查询结果将是 System.Collections.Generic.IEnumerable(Of Object) 类型。但是,您将结果分配给您以这种方式定义的变量Leases

Dim Leases As Object

对于以这种方式声明的变量,您无能为力。最好将它声明为查询返回的类型。

Dim Leases As System.Collections.Generic.IEnumerable(Of Object).

通过这种方式定义,Leases 可以通过在System.Linq.Enumerable 类中声明的方法进行扩展,从而允许调用Count 扩展方法。

【讨论】:

    【解决方案2】:

    典型地,带有 ADO.NET 和 Linq 的 DataTable 不能很好地处理通常类似于 List(Of (PocoObject)) 的新的类型良好的结构。但是,根据我的经验,通常您可以通过以下方式欺骗它:

    Sub Main()
       Dim dt As DataTable = New DataTable()
       dt.Columns.Add(New DataColumn("Id", GetType(Integer)))
       Dim row As DataRow = dt.NewRow()
       row("Id") = 1
       dt.Rows.Add(row)
       Dim row2 As DataRow = dt.NewRow()
       row2("Id") = 2
       dt.Rows.Add(row2)
    
       'Shows 2 rows
        Console.WriteLine(dt.Select().ToList().Count)
    
        Console.ReadLine()
    End Sub
    

    关键是 DataTable 没有“ToList()”扩展,直到您从中“选择”内容。恕我直言,带有 Linq 的 DataTable 就像在高速公路上以错误的方式驾驶汽车。因为没有什么是很好的类型,并且作为一些生产代码的示例,我必须从 WinForm 解决方案中的“数据集”中获取一些东西,然后只需将一组特定的列导出到 POCO 对象来制作我会拥有的列表做这样的事情:

    Dim ls = ds.Tables("tProduct").Select().Select(Function(x) New Product With {.ProductID = CInt(x("ProductId")?.ToString), .ProductDesc = x("ProductName")?.ToString}).ToList()
    

    有趣的东西。注意双重选择(),这不是错字。一个是 System.Data.DataTable 的扩展,一个是 System.Linq.Enumerable。所以你需要先选择才能选择lol。

    【讨论】:

    • 谢谢,这很有用!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-18
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    相关资源
    最近更新 更多