【问题标题】:Select statement on DataTable without where clause using Linq使用 Linq 在没有 where 子句的 DataTable 上选择语句
【发布时间】:2019-12-20 21:53:35
【问题描述】:

我有一段代码需要处理 DataTable。 DataTable 看起来像这样:

  PartnerID    |    Partner Name    |    GroupID    |    Group Name    |    Description
------------------------------------------------------------------------------------------
      1        |     First Name     |       4       |    Group Name1   |   Foo
      2        |     Second Name    |       12      |    Group Name2   |    Bar
      3        |     Third Name     |       7       |    Group Name3   |    Hello
      3        |     Third Name     |       8       |    Group Name4   |    Hello World

现在我要完成的是以下 SQL 语句的性能:

SELECT DISTINCT PartnerID, Partner Name
FROM Table1

在 C# 中使用 Linq,预期输出如下所示:

  PartnerID    |    Partner Name    |
-------------------------------------
      1        |    First Name      |
      2        |    Second Name     |
      3        |    Third Name      |

我已经看过以下帖子:

LINQ query on a DataTable

发现这对我的情况没有帮助,因为我真正想做的只是获取指定的列,但那里的所有答案都显示了一个解决方案,该解决方案似乎只适用于 where 语句或默认选择所有列。

我当前的代码现在看起来像这样:

     static void Main(string[] args)
     {
        DataTable fullTable = new DataTable();

        AddColumns(fullTable, "PartnerID", "Partner Name", "GroupID", "Group Name", "Description");

        fullTable.Rows.Add(1, "First Name", 4, "Group Name1", "Foo");
        fullTable.Rows.Add(2, "Second Name", 12, "Group Name2", "Bar");
        fullTable.Rows.Add(3, "Third Name", 7, "Group Name3", "Hello");
        fullTable.Rows.Add(3, "Third Name", 8, "Group Name4", "Hello World");

        var selectTwoCols = from arow in fullTable.AsEnumerable()
                            select arow; //how do i select specific columns from those rows?
        foreach (DataRow dataRow in selectTwoCols.Rows)
        {
            foreach (var item in dataRow.ItemArray)
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();
        }

    }

    static void AddColumns(DataTable table, params string[] columnNames)
    {
        for (int i = 0; i < columnNames.Length; i++)
        {
            table.Columns.Add(columnNames[i]);
        }
    }

我也愿意使用不同的类,尽管我仍然很想知道如何使用 DataTables 来解决这个问题

【问题讨论】:

  • 为什么不直接删除不需要的列?
  • 因为这不会使结果与众不同,并且可能不是这样做的预期方式,从 DataTable 类的“设计”来看
  • 首先我不会使用DataTable,这是一种非常古老的做事方式。
  • 在这种情况下,我很高兴知道当前的做事方式如何。虽然我仍然对如何使用数据表解决这个问题感到好奇
  • “当前方式”是使用域对象(类)来表示您的数据。就像Partner 类。

标签: c# .net linq select


【解决方案1】:
fullTable
   .AsEnumerable()
   .Select(x => new 
                { 
                   PartnerID = x.Field<int>("PartnerID"), 
                   PartnerName = x.Field<string>("Partner Name")
                })
   .Distinct();

这将创建一个具有您想要的两个属性的匿名类型。您比应用 Distinct 删除重复项。匿名类型为您处理 GetHashCodeEqualsDistinct 使用它们来识别重复项。

【讨论】:

  • 我在“new {...}”部分得到了无效的强制转换异常
  • PartnerID 是字符串吗?在这种情况下,将类型更改为字符串
  • 这不是我困惑的原因
  • @jdweng 你为什么这么认为?它在具有两个属性的匿名类上是不同的。它会正常工作的。
  • @jdweng 正如我在回答中所写,匿名类型将自动生成GetHashCodeEqualsdistinct 用于比较。您可以通过以下方式验证这一点:new[] { new { a = 1, b = "str"},new { a = 1, b = "str"} }.Distinct(),它将返回一个对象。
【解决方案2】:

我们已经在这里得到了很好的答案,但我认为这是一种更“有意”的方式。

除了 DataTable 类之外,C# 还提供了一个 DataView 类。

在该类文档中,我们可以阅读以下内容:

表示用于排序的 DataTable 的可数据绑定的自定义视图, 过滤、搜索、编辑和导航。

因此,据此判断,我认为 Microsoft 打算将此类与 DataTable 结合使用,以过滤掉行或列以及文档中提到的几乎所有操作。

所以我用了

DataView view = new DataView(fullTable); 

DataTable twoColsDistinct = view.ToTable(true, "PartnerID", "Partner Name"); //distinct
DataTable twoColsNonDistinct = view.ToTable(false, "PartnerID", "Partner Name"); //not distinct

要获得两个数据表,其中仅选择了两个必需的列并打印这两个数据表的内容会产生以下输出:

two cols distinct
----------------------
1 First Name
2 Second Name
3 Third Name
----------------------
two cols non distinct
----------------------
1 First Name
2 Second Name
3 Third Name
3 Third Name

这正是我所需要的。只是选择列。

使用以下代码会产生完全相同的输出:

var query = fullTable
               .AsEnumerable()
               .Select(x => new
                   {
                       PartnerID = x.Field<string>("PartnerID"),
                       PartnerName = x.Field<string>("Partner Name")
                   }
               ).Distinct();

foreach(var t in query)
{
    Console.WriteLine(t.PartnerID + " " + t.PartnerName);
}

打印

1 First Name
2 Second Name
3 Third Name

虽然我个人更喜欢上面更紧凑的解决方案,因为使用“更长”的解决方案,我们正在创建自定义对象(更准确地说:匿名类型),PartnerID 和 PartnerName 成为对象实例变量,在我的“简单”案例中,我一开始并没有处理任何面向对象的“东西”。

我发现紧凑型解决方案更易于阅读和理解。

奖金:

我们也可以使用相同的 DataView 对象来创建过滤后的 DataTables,这可能有用也可能没用:

view.RowFilter = "PartnerID > 1";

DataTable partnerIdGreaterThanOne = view.ToTable(true);

打印此 DataTable 会输出以下内容:

2 Second Name 12 Group Name2 Bar
3 Third Name 7 Group Name3 Hello
3 Third Name 8 Group Name4 Hello World

不确定在这里使用 Linq 是否更好。只是想把它扔出去。

编辑:

我做了一些性能测试,我发现使用

var query = fullTable
            .AsEnumerable()
            .Select(x => new
                    {
                        PartnerID = x.Field<string>("PartnerID"),
                        PartnerName = x.Field<string>("Partner Name")
                    })
            .Distinct();

如果不需要在 dataview 方法上创建的额外 DataTable 对象,则比 DataView 解决方案快很多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多