关于c#:从DataTable到DataTable的多个on子句通过LINQ

Multiple on clause from DataTable to DataTable via LINQ

我有一个关于林肯的问题我想要内部联接两个数据表,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    DataTable dt1 = new DataTable();
    DataTable dt2 = new DataTable();

    dt1.Columns.Add("TEST1");
    dt1.Columns.Add("TEST2");
    dt1.Columns.Add("TEST3");
    dt1.Columns.Add("TEST4");

    dt2.Columns.Add("TEST2");
    dt2.Columns.Add("TEST5");
    dt2.Columns.Add("TEST6");
    dt2.Columns.Add("TEST7");

    for (int i = 0; i < 10; i++)
    {
        DataRow row = dt1.NewRow();
        row["TEST1"] ="aaa";
        row["TEST2"] = string.Format("bbb-{0}{1}{2}", i, (i % 2 == 0 ?"-" :""), (i % 2 == 0 ?"ddd" :""));
        row["TEST3"] = i.ToString();
        row["TEST4"] ="ddd";
        dt1.Rows.Add(row);
    }

    for (int i = 0; i < 8; i++)
    {
        DataRow row = dt2.NewRow();
        row["TEST2"] ="bbb";
        row["TEST5"] = i.ToString();
        row["TEST6"] = i % 2 == 0 ?"ddd" :"";
        row["TEST7"] ="sss";
        dt2.Rows.Add(row);
    }

DT1的描述是:

1
2
3
4
5
6
7
8
9
10
11
12
TEST1 TEST2     TEST3 TEST4
---------------------------
aaa bbb-0-ddd   0       ddd
aaa bbb-1       1       ddd
aaa bbb-2-ddd   2       ddd
aaa bbb-3       3       ddd
aaa bbb-4-ddd   4       ddd
aaa bbb-5       5       ddd
aaa bbb-6-ddd   6       ddd
aaa bbb-7       7       ddd
aaa bbb-8-ddd   8       ddd
aaa bbb-9       9       ddd

DT2的描述是:

1
2
3
4
5
6
7
8
9
10
  TEST1 TEST5     TEST6  TEST7  
  ----------------------------  
  bbb     0         ddd    sss    
  bbb     1                sss    
  bbb     2         ddd    sss    
  bbb     3                sss    
  bbb     4         ddd    sss    
  bbb     5                sss    
  bbb     6         ddd    sss    
  bbb     7                sss

第一个问题是,我想加入DT1和DT2

1
2
3
4
5
6
7
8
9
10
 TEST2     TEST3   TEST7
---------------------------
bbb-0-ddd   0       sss
bbb-1       1       sss
bbb-2-ddd   2       sss
bbb-3       3       sss
bbb-4-ddd   4       sss
bbb-5       5       sss
bbb-6-ddd   6       sss
bbb-7       7       sss

所以我把代码写为下面的状态,我想把DT1和DT2加入到DT中。

1
2
3
4
5
6
7
8
9
10
11
    DataTable dt = new DataTable();
    dt.Columns.Add("TEST2");
    dt.Columns.Add("TEST3");
    dt.Columns.Add("TEST7");
    var result = from A1 in dt1.AsEnumerable()
                 join
                    A2 in dt2.AsEnumerable()
                 on
                    A1.Field<string>("TEST2") equals (A2.Field<string>("TEST2") +"-" + A2.Field<string>("TEST5") + (A2.Field<string>("TEST6") == string.Empty ?"-" : string.Empty) + A2.Field<string>("TEST6"))
                 select new dt.LoadDataRow(new object[] { A1.Field<string>("TEST2"), A1.Field<string>("TEST3"), A2.Field<string>("TEST7") }, false);
    result.CopyToDataTable();

但是它不起作用~此外,我想更改test3和test7的列,test3将命名为x1,test3将命名为x5,所以最新一行的代码应该是

选择new dt.loadDataRow(new object[]a1.field("test2"),x1=a1.field("test3"),x5=a2.field("test7"),false);

这是另一个问题……我该怎么办?是吗?是吗?


在Internet上,您可以找到一个非常有用的功能,称为LinqToDataTable(如下所附),通过它,您可以将任何查询Linq转换为DataTable,从而保留查询产生的数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 public DataTable LINQToDataTable<T>(IEnumerable<T> varlist)
        {
            DataTable dtReturn = new DataTable();
            PropertyInfo[] oProps = null;

            if (varlist == null) return dtReturn;

            foreach (T rec in varlist)
            {
                // Use reflection to get property names, to create table, Only first time, others will follow
                if (oProps == null)
                {
                    oProps = ((Type)rec.GetType()).GetProperties();
                    foreach (PropertyInfo pi in oProps)
                    {
                        Type colType = pi.PropertyType;

                        if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                        {
                            colType = colType.GetGenericArguments()[0];
                        }

                        dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
                    }
                }
                DataRow dr = dtReturn.NewRow();
                foreach (PropertyInfo pi in oProps)
                {
                    dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
                    (rec, null);
                }
                dtReturn.Rows.Add(dr);
            }
            return dtReturn;
        }

应轻松调用函数:

1
2
3
4
5
6
7
8
9
10
11
12
var result = (from A1 in dt1.AsEnumerable()
                          join
                             A2 in dt2.AsEnumerable()
                          on
                             A1.Field<string>("TEST2") equals (A2.Field<string>("TEST2") +"-" + A2.Field<string>("TEST5") + (A2.Field<string>("TEST6") == string.Empty ?"-" : string.Empty) + A2.Field<string>("TEST6"))
                          select new {
                                TEST2 = A1.Field<string>("TEST2"),
                                x1 = A1.Field<string>("TEST3"),
                                x2 = A2.Field<string>("TEST7")
                          });

            DataTable dtFinal = LINQToDataTable(result);

LoadDataRowCopyToDataTable方法不同,我更喜欢简单的foreach,在查询中添加这些行。这更清楚了,而且不依赖副作用。

可以在字符串上联接,并将这两行放在匿名类型中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var query = from r1 in dt1.AsEnumerable()
            join r2 in dt2.AsEnumerable()
            on r1.Field<string>("TEST2")
            equals string.Format("{0}-{1}-{2}"
                    , r2.Field<string>("TEST2")
                    , r2.Field<string>("TEST5")
                    , r2.Field<string>("TEST6"))
            select new { r1, r2 };

foreach (var bothRows in query)
{
    DataRow addedRow = dt.Rows.Add();
    addedRow.SetField("TEST2", bothRows.r1.Field<string>("TEST2"));
    addedRow.SetField("TEST3", bothRows.r2.Field<string>("TEST3"));
    addedRow.SetField("TEST7", bothRows.r2.Field<string>("TEST7"));
}