简体   繁体   中英

How to find the difference between two columns using LINQ query?

I have two data tables and would like to join the two tables to find the difference between the two columns, however it keeps returning null and erroring out at CopyToDataTable method as you cannot pass null into it. I have checked just before this code that there are exactly same data in TestOutput and ExpectedOutput tables. Here's my code:

IEnumerable<DataRow> diff =
  (from datarows1 in TestOutput.AsEnumerable()
   join datarows2 in ExpectedOutput.AsEnumerable() 
   on datarows1.Field<String>("external_id") equals datarows2.Field<String>("external_id")

   select new
   {
      KeyId = datarows1.Field<String>("external_id"),
      Difference = datarows1.Field<Decimal>("quantity") - datarows2.Field<Decimal>("quantity")
    }) as IEnumerable<DataRow>;

DataTable difference = diff.CopyToDataTable<DataRow>();

Error Message @ last row:

ArgumentNullException was unhandled - value cannot be null. Parameter name:source

The problem is the as IEnumerable<DataRow> cast. If you remove that line you will see that your query is selecting out an anonymous type with properties KeyID and Difference , not an IEnumerable. The as operator attempts to cast IEnumerable<DataRow> and returns a null if no such cast is possible. That is where your null reference exception is coming from.

To fix this, you need to find a different technique of populating the DataTable from your IEnumerable<a'> (where a' is the anonymous type)

DataTable difference = new DataTable();
difference.Columns.Add("KeyID", typeof(string));
difference.Columns.Add("Difference", typeof(decimal));

foreach (var result in diff)
   difference.Rows.Add(result.KeyID, result.Difference);

The problem is that when you do:

select new {...}

you are creating an anonymous class, not a DataRow. Hence when you cast it as IEnumerable<DataRow> it becomes null

If you use an implicitly typed variable:

 var diff = 
  (from datarows1 in TestOutput.AsEnumerable() 
   join datarows2 in ExpectedOutput.AsEnumerable()  
   on datarows1.Field<String>("external_id") equals datarows2.Field<String>("external_id") 

   select new 
   { 
      KeyId = datarows1.Field<String>("external_id"), 
      Difference = datarows1.Field<Decimal>("quantity") - datarows2.Field<Decimal>("quantity") 
    }); 

That will create a diff of the correct type.

You used anonymous types in your select new instead of this you should use some type which inherits from DataRow like your current table types:

.....
select new MyDataType
{
   external_id= datarows1.Field<String>("external_id"),
   quantity = datarows1.Field<Decimal>("quantity") 
              - datarows2.Field<Decimal>("quantity")
}) .ToList();

DataTable difference = diff.CopyToDataTable<DataRow>();

Actually your cast is not valid, and it'll be converted to null.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM