DataTable Linq多列连接

4

我需要对Linq Join进行翻译帮助。我想要连接两个表格,它们拥有相同的n列结构。我的问题是我不知道这些列的名称,那么我如何在 select new 中重新编写它们呢?

表1:这里我有一些ID、姓名和姓氏参数。评论、属性和其他内容为空。

 ID    Name   LastName  Comment   Attribute ...     
                         "what"   "ABC"     ...
                         "hello"  "SDE"     ...
 3     lola               
 1              de           
 4     miki      
 ...   ...      ...      ...  

表格2:这个表格与表格1相似,但在注释、属性和其余方面有一些参数。

 ID    Name   LastName  Comment   Attribute ...
                        "what"   "ABC"     ...
                        "hello"  "SDE"     ...
 1              de       "hi"     
 4     miki                      "OKK"
 3     lola             "yo"     "LL"

结果:我想要像这样加入表格
 ID    Name   LastName  Comment   Attribute ...
                        "what"   "ABC"     ...
                        "hello"  "SDE"     ...
 3     lola               "yo"    "LL" 
 1               de        "hi"   
 4     miki                       "OKK"
 ...   ...      ...      ...       ...     ...

我的代码如下:

var Result= from tb1 in table1.AsEnumerable()
            join tb2 in tabl2.AsEnumerable()
            on new
            {                
             Name = tb1.Field<String>("Name"),
             LastName = tb1.Field<String>("LastName"),
             } equals new
            {
             Name=tb2.Field<String>("Name"),
             LastName=tb2.Field<String>("LastName"),
             }
            into grp1
            from tb3 in grp1.DefaultIfEmpty()
            select new
    {
     ID = tb1.Field<String>("ID"),
     Name = tb1.Field<String>("Name") ,
     LastName = tb1.Field<String>("LastName"),
     Comment = tb3!= null ? tb3.Field<String>("Comment") : null,
     Attribute= tb3!= null ? tb3.Field<String>("Attribute") : null,
     ...
     // Here should be next Columns Name but don't know how to put there

     };

我尝试使用这段代码,但我的编译器就是无响应了,不知道为什么。
        for (int i = 2; i < table1.Rows.Count; i++)
        {
            foreach (DataRow dr in table2.Rows)
            {
                if ((table1.Rows[i]["Name"].ToString() == dr["Name"].ToString())&&table1.Rows[i]["LastName"].ToString() == dr["LastName"].ToString())
                {
                    table1.Rows.RemoveAt(i);
                    table1.ImportRow(dr);

                }
            }
        }
        dataGridView1.DataSource = table1;

我认为我应该使用ToDictionary,但不知道如何使用。 - Uni Le
只是一个问题,为什么您需要合并它们?Table2似乎包含整个Table1?如果有帮助的话,您可以查看这个问题https://dev59.com/OnRB5IYBdhLWcg3wFz8g。那么ID呢?在冲突的情况下应该如何处理?冲突数据等等... - flindeberg
我想加入它们,因为我想要像表1中一样拥有ID、姓名和姓氏。在表2中,有时会缺少ID、姓氏和姓名。这就是为什么我使用外部左连接的原因。 - Uni Le
如果将Linq结果转换为Datatable,则可以按列索引选择。请参阅http://stackoverflow.com/questions/2361852/how-to-access-columns-by-index-in-linq。 - Paul D'Ambra
问题在于Linq结果未完成,这是个糟糕的例子。 - Uni Le
显示剩余2条评论
3个回答

1

你觉得加入后,从table1的行中复制三个已知字段到table2的行中如何?

var copiedTable2 = table2.Copy(); // Copy table2 if you don't want it to be modified

var items = from tb1 in table1.AsEnumerable()
            join tb2 in copiedTable2.AsEnumerable()
            on new
            {                
                Name = tb1.Field<String>("Name"),
                LastName = tb1.Field<String>("LastName"),
            } equals new
            {
                Name=tb2.Field<String>("Name"),
                LastName=tb2.Field<String>("LastName"),
            }
            into grp1
            from tb3 in grp1.DefaultIfEmpty()
            select new
            {
                ID = tb1.Field<String>("ID"),
                Name = tb1.Field<String>("Name") ,
                LastName = tb1.Field<String>("LastName"),
                Row = tb3 ?? table2.NewRow();
            };

 foreach(var item in items)
 {
     item.Row.SetField<String>("ID", item.ID);
     item.Row.SetField<String>("Name", item.Name);
     item.Row.SetField<String>("LastName", item.LastName);
 }

 var rows = items.Select(x => x.Row);

 // How to set the rows as a DataGridView's DataSource
 var result = table2.Clone();
 foreach(var row in rows)
 {
     result.Rows.Add(row.ItemArray);
 }
 dataGridView.DataSource = result;

谢谢Risky,非常好的想法,但是它如何在DataGridView中显示呢?我只有ID、Name、LastName和Row列,其中Row列具有System.Data.Row参数。我该如何扩展它? - Uni Le
@UniLe:您可以使用新的DataRows填充一个DataTable,并将其分配给DataGridView的DataSource。我不确定如何从DataRow创建一个匿名对象。 - Risky Martin
有风险:我得到了错误信息“此行已属于另一个表”。在 result.Rows.Add(row); 处。 - Uni Le
@UniLe:非常感谢你!但是现在我想一想,你最新的例子已经非常接近可行并且更短了。我会尝试让它正常运行。 - Risky Martin
为了减少重复,我会这样做:var rows = item.Select(x=>x.Row).Distinct(); 还有一个问题,如果我在表1中拥有另一个对象并尝试与没有该对象的表2绑定,它不会显示出来,这是为什么? 我能否改变您的代码以获取左外连接? - Uni Le
好的,我通过使用第二段代码解决了问题,它完美地工作。 - Uni Le

1
对于表1中的每一行1,如果在表2中存在匹配的行2,则使用行2。否则,使用行1。
var newTable = table1.Clone();
foreach (DataRow row1 in table1.Rows) // To skip the first 2, use table1.Rows.Cast<DataRow>().Skip(2)
{
    var row = table2.Rows.Cast<DataRow>().FirstOrDefault(row2 => 
                row1["Name"].ToString() == row2["Name"].ToString() &&
                row1["LastName"].ToString() == row2["LastName"].ToString()) ?? row1;
    newTable.ImportRow(row);
}
dataGridView1.DataSource = newTable;

冒险:我遇到了错误,无法将[]索引应用于表达式类型对象row1。 - Uni Le
冒险的:好的,我知道了,我应该使用 DataRow row1 而不是 var row1,非常感谢你的帮助... 运行得很好。 - Uni Le

1
尝试一下,不需要使用循环。
var resultTable = from tb1 in table1.AsEnumerable()
                   join tb2 in tabl2.AsEnumerable()
                   on tb1["Name"].ToString() equals tb2["Name"].ToString()
                   where tb1["LastName"].ToString() == tb2["LastName"].ToString()
                   select r;

 DataTable resultTable =result.CopyToDataTable();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接