Left Outer Join - LINQ to Datatable

Ashish Charan picture Ashish Charan · Jun 19, 2013 · Viewed 14.1k times · Source

I'm trying to apply a left outer join using LINQ on two data tables. I'm receiving the exception listed below when I try to debug and view data contained in result variable:

System.ArgumentException: Value cannot be null. Parameter name: row

Code:

private DataTable DataTable1()
{
    DataRow dataRow = null;
    DataTable dt1 = new DataTable();
    dt1.Columns.Add("EmpId");
    dt1.Columns.Add("EmpName");
    dataRow = dt1.NewRow();
    dataRow["EmpId"] = "EMP001";
    dataRow["EmpName"] = "Ajaj Kumar";
    dt1.Rows.Add(dataRow);
    dataRow = dt1.NewRow();
    dataRow["EmpId"] = "EMP002";
    dataRow["EmpName"] = "Sanjay Gupta";
    dt1.Rows.Add(dataRow);
    dataRow = dt1.NewRow();
    dataRow["EmpId"] = "EMP003";
    dataRow["EmpName"] = "Ashish Charan";
    dt1.Rows.Add(dataRow);
    dt1.AcceptChanges();
    return dt1;
}

private DataTable DataTable2()
{
    DataRow dr = null;
    DataTable dt2 = new DataTable();
    dt2.Columns.Add("EmpId");
    dt2.Columns.Add("Salary");
    dr = dt2.NewRow();
    dr["EmpId"] = "EMP001";
    dr["Salary"] = "50000";
    dt2.Rows.Add(dr);
    dr = dt2.NewRow();
    dr["EmpId"] = "EMP002";
    dr["Salary"] = "45000";
    dt2.Rows.Add(dr);
    dt2.AcceptChanges();
    return dt2;
}

private void Form1_Load(object sender, EventArgs e)
{
    var empInfo = DataTable1().AsEnumerable();
    var empSal = DataTable2().AsEnumerable();

    var result = from dtEmpRow in empInfo
            join dtEmpSal in empSal
            on dtEmpRow.Field<string>("EmpId") equals dtEmpSal.Field<string>("EmpId")
            into outer
            from dtEmpSal in outer.DefaultIfEmpty()
            select new
            {
                Id = dtEmpRow.Field<string>("EmpId"),
                Name = dtEmpRow.Field<string>("EmpName"),
                Salary = ((dtEmpRow == null) ? "(no salary)" : dtEmpSal.Field<string>("Salary"))
            };
}

Answer

Sergey Berezovskiy picture Sergey Berezovskiy · Jun 19, 2013

That is because here dtEmpSal is null (default case if sequence is empty):

from dtEmpSal in outer.DefaultIfEmpty() // dtEmpSal is null

When you are trying to call Field<T> extension on DataRow which is null, you get that exception:

dtEmpSal.Field<string>("Salary") // System.ArgumentException

Fix it with ternary operator. You was near, but checked wrong value:

from dtEmpRow in empInfo
join dtEmpSal in empSal
    on dtEmpRow.Field<string>("EmpId") equals dtEmpSal.Field<string>("EmpId")
into outer
from dtEmpSal in outer.DefaultIfEmpty()
select new
{
    Id = dtEmpRow.Field<string>("EmpId"),
    Name = dtEmpRow.Field<string>("EmpName"),
    // here instead of dtEmpRow you should check dtEmpSal
    Salary = (dtEmpSal == null) ? "(no salary)" : dtEmpSal.Field<string>("Salary")
};