tags:

views:

60

answers:

3

I've got three objects (splistitemcollection) that im joining together which is working great but the problem im having is that there are a one to many relationship between the a contract object and a customers object. I need to grab just just the first customers object for each contract object during the join.

Here is what I am getting

(Contract)(Customer)
12345  John Smith
12345  Jane Smith
67890  howard Jones
67890  Mary Jones

Here is what I want 12345 (just one of the customers, jane or john)

Here is the code im currently using.

  var joinedResults = from SPListItem contracts in _contractList
                      join SPListItem customers in _customerList
                      on contracts["ContractNumber"] equals customers["ContractNumber"]  
                      join SPListItem loans in _loanList
                      on contracts["ContractNumber"] equals loans["Contract_x0020_Number"] 
                      into l from loans in l.DefaultIfEmpty()
                      select new MergedData(contracts, customers, loans);

In SQL i'd define a select top clause in a subquery defined on my join, I just cant wrap my head around the syntax for my newbie linq brain.

Final result

  var joinedResults = from SPListItem contracts in _contractList
      join SPListItem customers in 
      // Derived subset
        (from SPListItem customers in _customerList
        group customers by customers["ContractNumber"] into groupedCustomers 
        select groupedCustomers.FirstOrDefault()
      )  on contracts["ContractNumber"] equals customers["ContractNumber"]  
      join SPListItem loans in _loanList
      on contracts["ContractNumber"] equals loans["Contract_x0020_Number"] into l
      from loans in l.DefaultIfEmpty()
      select new MergedData(contracts, customers, loans);
A: 
var joinedResults =   (from SPListItem contracts in _contractList
                      join SPListItem customers in _customerList
                      on contracts["ContractNumber"] equals customers["ContractNumber"]  
                      join SPListItem loans in _loanList
                      on contracts["ContractNumber"] equals loans["Contract_x0020_Number"] 
                      into l from loans in l.DefaultIfEmpty()
                      select new MergedData(contracts, customers, loans)).FirstOrDefault();

Just call FirstOrDefault method to select the first item found.

AS-CII
thanks for the answer, and I realized I am missing a critical part of my description. I want all records from the contracts, and only one of hte matching records from customers. So basically FirstOrDefault is right, but only on the customers. Would something like this work?
brian brinley
+1  A: 

I'll explain it first, because the LINQ sometimes looks confusing. The idea is to take your customers query, and group by the ContractNumber, and then take the first. If you want you could order by some field, to have it be more deterministic (always taking the name lowest in alphabetical order, etc.) You then just join on your tempQuery which will be basically the distinct(ContractNumber) and first customer.

var tempQuery =  from SPListItem customers in _customerList
    group customers by customers["ContractNumber"] into gby 
    select gby.First();


var joinedResults =

    from SPListItem contracts in _contractList
    join SPListItem customer in tempQuery
on contract["ContractNumber"] equals customer["ContractNumber"]
    join SPListItem loans in _loanList
on contracts["ContractNumber"] equals loans["Contract_x0020_Number"] 
into l from loans in l.DefaultIfEmpty()
select new MergedData(
     contracts, 
     customer, 
     loans
   );

}
Nix
thank you very much, I'm certainly more into the concept understanding than just a code syntax and that certainly makes sense to break the seperation out, i'd imagine that would be faster performance as well instead of having to join on every row and then filter for only the first.
brian brinley
My SP VM isn't playing nice this morning, so I just tested the above out (With ListItemCollection and ListItem) and it should do what you want. Does the above make sense?
Nix
A: 

This is like a Top (1) point query for each contract returned:

var joinedResults = from SPListItem contracts in _contractList
                      join SPListItem loans in _loanList
                      on contracts["ContractNumber"] equals loans["Contract_x0020_Number"] 
                      into l from loans in l.DefaultIfEmpty()
                      select new MergedData(contracts, 
                      customer = _customerList.Where( c => c["ContractNumber"] == contracts["ContractNumber"].FirstOrDefault()
                      , loans);
Sorax