Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get only one (last) record in one-to-many join with linq-to-entities

I have the following in linq-to-entities

clientprojects = (from p in this.SAPMappingEntities.SAP_Master_Projects 
join c in this.SAPMappingEntities.SAP_Master_ProjectPartners on c.project_no equals p.project_no
where c.partner_name.Contains(clientstring)
orderby p.start descending 
select new ClientProjects { client = c.partner_name, location = c.city +", "+c.region, project_no = c.project_no, start_dt = p.start, end_dt = p.finish }).Take(50).ToList();

I would like change this query so that for each SAP_Master_Project only get the SAP_Master_ProjectPartners record which has the latest update_dt. How can I do this?

EDIT

There's a project table with a project number and project details including project start and end dates. There's a project partners table with the project partner number, name, project number, update date and other details.

SAP_MASTER_PROJECT

project_no

start

finish

SAP_MASTER_PROJECTPARTNERS

partner_no

project_no

partner_name

city

region

update_dt

When the user enters "ABC" into a text box, the info I want to return is the project number, project start date, project end date plus project partner name, city, and state from the last project partner record for the last 50 projects (based on start date) where the project partner name contains or is like "ABC".

I'm sure there's more than one way to do this, but his SQL gives me the results that I need:

SELECT TOP 50 p.project_no, p.start, p.finish, c.partner_name, c.city, c.region
FROM 
(select pp.project_no, pp.partner_name, pp.city, pp.region
from SAP_Master_ProjectPartners pp
where pp.partner_name LIKE @clientstring AND pp.update_dt = (select max(pp1.update_dt)
                       from SAP_Master_ProjectPartners pp1
                       where pp1.project_no = pp.project_no)) c
join SAP_Master_Projects p
on (p.project_no = c.project_no)
ORDER BY p.start DESC

EDIT #2 That sql actually returns a few items which have the same update_dt, so I modified the sql to below. Still struggling to convert to linq.

SELECT TOP 50 p.project_no, p.start, p.finish, c.partner_name, c.city, c.region, c.update_dt, c.row_id
FROM SAP_Master_Projects p
join
(select pp.project_no, pp.partner_name, pp.city, pp.region, pp.update_dt, pp.row_id
from SAP_Master_ProjectPartners pp
where pp.partner_name LIKE @clientstring AND pp.row_id = (select TOP 1 row_id
                       from SAP_Master_ProjectPartners pp1
                       where pp1.project_no = pp.project_no order by update_dt DESC)) c
on (p.project_no = c.project_no) where p.active_flag = 1
ORDER BY p.start DESC
like image 505
RememberME Avatar asked Oct 27 '11 03:10

RememberME


2 Answers

This query would probably be simpler if you defined an entity relationship between SAP_Master_Projects and SAP_Master_ProjectPartners so the join could be implicit instead of explicit.

Edit Since you can't do that, something like this might work (using let and doing a logical join within a where clause):

var clientProjects =
    (
        from p in entities.SAP_Master_Projects
        let c = entities.SAP_Master_ProjectPartners
            .Where(cl => cl.partner_name.Contains(clientstring)
                && cl.project_no == p.project_no
                )
            .OrderBy(cl => cl.update_dt) // Todo: Might need to be descending?
            .FirstOrDefault()
        where c != null
        orderby p.start descending
        select new ClientProjects
        {
            client = c.partner_name,
            location = c.city + ", " + c.region,
            project_no = c.project_no,
            start_dt = p.start,
            end_dt = p.finish
        }
        )
    .Take(50)
    .ToList()
    ;
like image 79
Merlyn Morgan-Graham Avatar answered Oct 19 '22 03:10

Merlyn Morgan-Graham


It sounds like you're trying to come up with the following query:

SELECT *
  FROM MasterProjects p
       INNER JOIN (SELECT project_no,
                          partner_name
                     FROM ProjectPartners o
                    WHERE o.update_dt = (SELECT MAX(update_dt)
                                           FROM ProjectPartners i
                                          WHERE i.project_no = o.project_no)) c
               ON p.project_no = c.project_no
              AND p.partner_name = c.partner_name

I'm not entirely sure how to translate this in to LINQ but here is my best attempt:

var clientprojects =
    from p in MasterProjects
    join c in ProjectPartners on p.project_no == c.project_no
   where c.partner_name == (from o in ProjectPartners
                           where o.project_no == c.project_no
                             and o.update_dt == (from i in ProjectParters
                                                where o.project_no = i.project_no
                                               select i.update_dt).Max()
                          select o.partner_name).First();

The above LINQ may not even compile, but hopefully it'll send you in the right direction.

like image 42
Joshua Avatar answered Oct 19 '22 04:10

Joshua