【问题标题】:LINQ to DataSet - Joins and GridView IssuesLINQ to DataSet - 连接和 GridView 问题
【发布时间】:2011-04-07 21:17:37
【问题描述】:

我需要将三个 DataTable 连接在一起,并将连接的数据用作 GridView 的 DataSource。第一个 (localSQLTable) 通过针对 MS-SQL 数据库的查询填充。后两个(serviceResponse.Tables(0)serviceResponse.Tables(1))是使用来自 Web 服务结果的 DataSet.ReadXML 构建的。

我已经走到这一步了:

Dim joinedData = From f In localSQLTable _
                 Join s1 As DataRow In serviceResponse.Tables(0) _
                 On f.Item("KNum") Equals s1.Item("Number") _
                 Join s2 As DataRow In serviceResponse.Tables(1) _
                 On s1.Item("KNumber_Id") Equals s2.Item("KNumber_Id") _
                 Select Guid = f.Item("Guid"), Num = f.Item("Num"), Desc = f.Item("Desc"), KNum = f.Item("KNum"), KDesc = s2.Item("KDescription_Text"), Type = s2.Item("Type") _
                 Where (Type.ToString.ToUpper = "LONG_HTML")

myGridView.DataSource = joinedData
myGridView.DataBind()

但是,joinedData 似乎只是一个 IEnumerable(匿名类型)。我尝试了一些方法,包括以下内容:

  • 尝试使用 lambda 函数(我完全不熟悉)将 joinedData 构建为 IEnumerable(Of DataRow) 以构建新的 DataRow
  • 在结果集上调用 .ToList().AsEnumerable()(在玩弄类型之后)

主要问题是,无论我尝试什么,使用结果作为我的 GridView 的数据源都有问题 - 我遇到了两个例外之一:

  • ID 为 GridView 的数据源没有任何属性或属性可用于生成列。确保您的数据源有内容。
  • 数据源不支持服务器端数据分页。

我也知道我可能不应该在我的 Linq 查询中使用 .Item ("Field") 而不是强类型的 .Field (Of T)("Field") - 我一直在等待该更改,直到我得到实际可用的数据。

我没有和 Linq 结婚;如果DataSet.Merge 更合适(或其他一些方法),我会接受的。还有一个明显的可能性是,我实际上必须稍后将我所拥有的内容加入另外两个 DataTable。如果是这种情况,我可能会将serviceResponse 表合并为一个,因此我仍然只会加入三个表。

那么我该怎么做才能将这些数据连接在一起并将结果用作我的 GridView 的数据源?我正在做的任何事情都会比在我的原始数据表 (localSQLTable) 中添加两个额外的列并使用 XML 响应数据逐行填充它们更快吗?

【问题讨论】:

    标签: .net asp.net vb.net linq linq-to-dataset


    【解决方案1】:

    在您的 SELECT 中改用 f.Field<Guid>("Guid")

    示例(C#)

    gv.DataSource = serviceResponse.Tables[0].AsEnumerable().Select(r => new { Name = r.Field<Guid>("Guid") });
    gv.DataBind();
    

    示例 (vb)

    gv.DataSource = dt.AsEnumerable().Select(Function(r) New With { .Name = r.Field(Of Guid)("Guid") })
    gv.DataBind()
    

    或者在 GridView 上禁用 AutoGenerateColumns

    编辑: 以下查询工作正常

    void Main()
    {
        var dt1 = new DataTable();
        dt1.Columns.Add("Col1", typeof(string));
    
        var dt2 = new DataTable();
        dt2.Columns.Add("Col2", typeof(string));
    
        var row = dt1.NewRow();
        row[0] = "test";
        dt1.Rows.Add(row);
    
        row = dt2.NewRow();
        row[0] = "test";
        dt2.Rows.Add(row);
    
        var gv = new GridView();
        gv.DataSource = from t1 in dt1.AsEnumerable()
                        join t2 in dt2.AsEnumerable()
                            on t1[0] equals t2[0]
                        select new
                        {
                            Name1 = t1.Field<string>(0),
                            Name2 = t2.Field<string>(0)
                        };
        gv.DataBind();
    }
    

    【讨论】:

    • 抱歉让您久等了。我希望 AutoGenerateColumns 保持真实 - 我会尽快尝试并回复您。
    • 没用 - 看起来像一个铸造问题,也许我需要明确选择数据行。我得到以下信息:Unable to cast object of type '&lt;horrible long string saying it's an anonymous type' to type 'System.Collections.Generic.IEnumerable'1[System.Data.DataRow]'.
    • 您要在表格上添加 AsEnumerable()?
    • 我将.AsEnumerable() 添加到我上面加入的三个表中。
    • 看起来问题是因为我在两个数据表上进行连接,所以我的匿名类型包含两个数据行。给出的代码适用于单一数据源,但通过我的加入,我将不得不想出一种方法来返回具有我需要的确切模式的 DataRow,它包含我的数据组合。
    【解决方案2】:

    这一切的最终结果如下:

    Dim joinedData As Generic.IEnumerable(Of DataRow) = (From f In localSQLTable.AsEnumerable() _
                                                         Join h In serviceResponse.Tables(0).AsEnumerable() _
                                                         On h.Item("serviceknum") Equals f.Item("knum") _
                                                         Select GetFinalDataRow(finalTable, f, h))
    
    gvGridOne.DataSource = joinedData.CopyToDataTable()
    gvGridOne.DataBind()
    

    我明确定义了我需要的结束 DataTable 的 DataTable 和架构(通过添加 DataColumns),然后将该 DataTable 和我的 join 中的两个 DataRows 传递给GetFinalDataRow(),定义为:

    Public Function GetFinalDataRow(ByRef FinalTable As DataTable, ByVal Row1 As DataRow, ByVal Row2 As DataRow) As DataRow
        Dim newRow As DataRow = FinalTable.NewRow()
        For Each col As DataColumn In FinalTable.Columns
            If Row1.Table.Columns.Contains(col.ColumnName) Then
                newRow(col.ColumnName) = Row1.Item(col.ColumnName)
            ElseIf Row2.Table.Columns.Contains(col.ColumnName) Then
                newRow(col.ColumnName) = Row2.Item(col.ColumnName)
            Else
                newRow(col.ColumnName) = ""
            End If
        Next
    
        Return newRow
    End Function
    

    我的joinedData 对象现在是DataRows 的IEnumerable,我可以将它复制到我的GridView 数据源的DataTable 中,它会自动生成列并允许分页。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-13
      • 1970-01-01
      • 2013-05-24
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多