简体   繁体   中英

List<T> joins DataTable

I have a List of objects (lst) and DataTable (dt). I want to join the lst and dt on the common field (code as string) and need to return all matching rows in the lst.

My List contains two columns ie code and name along with values below:

code name
==== ====    
1    x    
2    y    
3    z

The DataTable contains two columns ie code and value along with values below:

code value
==== =====    
3    a    
4    b    
5    c

The result is:

3   z

Below is my code; but I know it is not a correct statement and thus seeking your advice here. I would be much appreciated if you could guide me on how to write the correct statement.

var ld = from l in lst
         join d in dt.AsEnumerable() on l.code equals d.code
         select new { l.code, l.name };

You can try any of the below.

var ld = from l in lst
     join d in dt.AsEnumerable() on l.code equals d.Field<int>("code")
     select new { l.code, l.name };

var ld = lst.Join(dt.AsEnumerable(), l => l.code, d => d.Field<int>("code"), (l,d) => new { l.code, l.name });

You can use Linq query or Join extension method to join the collection on code. Just that when you select data from datatable, you need to use dt.Field method. Please use either of the following code.

Query1:

var ld = lst.Join(dt.AsEnumerable(),
            l => l.code,
            d => d.Field<string>("code"),
            (l, d) => new
            {
                l.code,
                l.name,
                value = d.Field<string>("value")
            }).ToList();

Query2:

var ld = (from l in lst
          join d in dt.AsEnumerable()
          on l.code equals d.Field<string>("code")
          select new
          {
              l.code,
              l.name,
              value = d.Field<string>("value")
          }).ToList();

Query3:

var ld = (from l in lst
          join d in dt.AsEnumerable()
          on l.code equals d.Field<string>("code")
          let value = d.Field<string>("value")
          select new
          {
              l.code,
              l.name,
              value
          }).ToList();

It's not clear what your required output is but it looks as if you are correctly getting the only common records. You could extend your select to

select new { l.code, l.name, d.value }

Which would give all the data/columns from both tables.

code name value
==== ==== =====
  3    z     a

Try this:

var ld = from l in lst
         join d in dt.Cast <DataRow>() on l.code equals d["code"].ToString()
         select new { l.code, l.name };

SO you have a List and a DataTable. You don't plan to use the Values of the DataTable, only the Codes.

You want to keep those List items, that have a Code that is also a code in the DataTable.

If you plan to use your DataTable for other things than just for this problem, My advice would be to first create a procedure to convert your DataTable into an enumerable sequence.

This way you can add LINQ statements, not only for this problem, but also for other problems.

Let's create an extension method for your DataTable that converts the data into the items that are in the DataTable. See extension methods demystified.

Alas, I don't know what's in your DataTable, let's assume that your DataTable contains Orders

class CustomerOrder
{
    public int Id {get; set;}
    public int CustomerId {get; set;}

    public int Code {get; set;}
    public string Value {get; set;} 
    ...
}

The extension method that extends functionality of class DataTable:

public static IEnumerable<Order> ToCustomerOrders(this DataTable table)
{
    return table.AsEnumerable().Select(row => new CustomerOrder
    {
        Id = ...
        CustomerId = ...
        Code = ...
        Value = ...
     };
}

I'm not really familiar with DataTables, but you know how to convert the cells of the row into the proper value.

Usage:

DataTable table = ...
Int customerId = 14;

var ordersOfThisCustomer = table.ToCustomerOrders
    .Where(customerOrder => customerOrder.CustomerId == customerId)
    .FirstOrDefault();

In words: convert the datatable into CustomerOrders, row by row, and check for every converted CustomerOrder whether it has a CustomerId equal to 14. Stop if found. return null if there is no such row.

Now that you've got a nice reusable procedure that is also easy to test, debug and change, we can answer your question.

Given a DataTable with CustomerOrders, and a sequence of items that contain Code and Name , keep only those items from the sequence that have a Code that is also a Code in the DataTable.

var dataTable = ...   // your DataTable, filled with CustomerOrders.
var codeNames = ...   // your list with Codes and Names

var codesInDataTable = dataTable.ToCustomerOrders
    .Select(customerOrder => customerOrder.Code)
    .Distinct();

This will create an enumerable sequence that will convert your DataTable row by row and extract property Code. Duplicate Code values will be removed.

If Codes are unique, you don't need Distinct.

Note: the enumerable sequence is not enumerated yet!

var result = codeNames
    .Where(codeName => codesInDataTable.Contains(codeName.Code))
    .ToList();

In words: for every [Code, Name] combination in your list, keep only those [Code, Name] combinations that have a value for Code that is also in codesInDataTable .

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