Question

I have a question about joins in LINQ. I am currently converting an access application to .NET where data is retrieved from two different databases on two different servers. In the old application the data could be retrieved by one query:

SELECT *, tbl2.Descr, tbl2.Form FROM tbl2 RIGHT JOIN tbl1 ON tbl2.proId2 = tbl1.proId

I found that one way to do this in .NET is retrieving the two tables seperatly and then joining them with LINQ. I have no experience in LINQ so I may be completely wrong with my logic or code because I can't seem to get it working.

First I tried to do a normal join (no right) but then only 18 rows are returned when the two tables contain almost 2000 rows. I also checked the data and it should definitly result in more rows, there are not that many empty cells. So then I put together a right/left join but this actually results in an error. When I debug it, everything's fine when the LINQ statement is executed but when I go into the foreach, an error is shown and the error is actually indicated in the linq statement, saying table2 is empty. When I check table1 I also see only 22 datarows.

What am I doing wrong?

DataTable dtTarget= data1.Clone();
var dt2Columns = data2.Columns.OfType<DataColumn>().Select(dc =>
     new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping));
var dt2FinalColumns = from dc in dt2Columns.AsEnumerable()
                    where dtTarget.Columns.Contains(dc.ColumnName) == false
                              select dc;

dtTarget.Columns.AddRange(dt2FinalColumns.ToArray());

var results = from table1 in data1.AsEnumerable()
              join table2 in data2.AsEnumerable() 
              on table1.Field<String>("proId") equals table2.Field<String>("proId2")
              select table1.ItemArray.Concat(table2.ItemArray).ToArray();

foreach (object[] values in results)
            dtTarget.Rows.Add(values);

Outer Join:

var results = from table1 in data1.AsEnumerable()
              join table2 in data2.AsEnumerable() on table1.Field<String>("proId")     equals table2.Field<String>("proId2") into t_join
              from table2 in t_join.DefaultIfEmpty(null) select table1.ItemArray.Concat(table2.ItemArray).ToArray();
Was it helpful?

Solution

I notice you're using strings as the join keys. Perhaps the string comparison is different between the environments (access vs .net). Access may use a case-insensitive compare, while .net's default is case-sensitive.

To make .net use a case-insensitive compare, here's the first query:

var results = data1.AsEnumerable()
  .Join(
    data2.AsEnumerable(),
    row1 => row1.Field<String>("proId"),
    row2 => row2.Field<String>("proId2"),
    (row1, row2) => row1.ItemArray.Concat(row2.ItemArray).ToArray(),
    StringComparer.InvariantCultureIgnoreCase); //and now caps are ignored.

and second query:

var results = data1.AsEnumerable()
  .GroupJoin(
    data2.AsEnumerable(),
    row1 => row1.Field<String>("proId"),
    row2 => row2.Field<String>("proId2"),
    (row1, row2s) => new {Row1 = row1, Row2s = row2s},
    StringComparer.InvariantCultureIgnoreCase)
  .SelectMany(
    x => x.row2s.DefaultIfEmpty(null)),
    (x, row2) => row2 == null ? x.Row1.ItemArray : x.Row1.ItemArray.Concat(row2.ItemArray).ToArray()
  );
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top