【问题标题】:Get only one (last) record in one-to-many join with linq-to-entities在与 linq-to-entities 的一对多连接中仅获取一个(最后一个)记录
【发布时间】:2011-10-27 03:08:25
【问题描述】:

我在 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();

我想更改此查询,以便为每个 SAP_Master_Project 仅获取具有最新 update_dt 的 SAP_Master_ProjectPartners 记录。我该怎么做?

编辑

有一个项目表,其中包含项目编号和项目详细信息,包括项目开始和结束日期。有一个项目合作伙伴表,其中包含项目合作伙伴编号、名称、项目编号、更新日期和其他详细信息。

SAP_MASTER_PROJECT

project_no

开始

完成

SAP_MASTER_PROJECTPARTNERS

partner_no

project_no

合作伙伴名称

城市

地区

update_dt

当用户在文本框中输入“ABC”时,我要返回的信息是项目编号、项目开始日期、项目结束日期加上项目合作伙伴名称、城市和状态,来自最后一个项目合作伙伴记录项目合作伙伴名称包含或类似于“ABC”的最近 50 个项目(基于开始日期)。

我确信有不止一种方法可以做到这一点,但他的 SQL 为我提供了我需要的结果:

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

编辑 #2 该sql实际上返回了一些具有相同update_dt的项目,所以我将sql修改为下面。仍在努力转换为 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

【问题讨论】:

  • 你能提供一些关于你的实体结构的细节吗?您提到了 update_dt,但很难确定确切的位置。另外,您能否澄清一下您是否需要将 ClientProjects 包含在此查询中?
  • 每个项目有一个 SAP_Master_Project 条目。每个项目有多个 SAP_Master_ProjectPartners 条目。我想将 SAP_Master_Project 与 SAP_Master_ProjectPartners 与最后一个 SAP_Master_ProjectPartners.update_dt 一起加入。对于每个项目/项目合作伙伴组合,我想返回一个条目(最后一个)。
  • 对我来说,您的架构没有意义的一件事是,您似乎正在尝试提供历史记录,但您实际上是在像多对一关系一样创建数据库.似乎是一个糟糕的数据库设计,因为您真的应该将历史记录保存在一个单独的表中(甚至可能是一个单独的模型)。如果您在此处尝试进行更改,则永远无法为单个项目建模多个合作伙伴。合作伙伴只能有一个项目。看起来你真的应该有第三张关系表,让它多对多
  • 这可以让您保留历史记录,因为您可以更新映射以指向最新的。
  • 这些表已经存在了很长时间,并被多个应用程序使用。我只想查询这些数据以在屏幕上显示给用户。

标签: c# linq join linq-to-entities one-to-many


【解决方案1】:

如果您在 SAP_Master_ProjectsSAP_Master_ProjectPartners 之间定义实体关系,则此查询可能会更简单,因此连接可以是隐式的而不是显式的。

编辑因为你不能这样做,这样的事情可能会起作用(使用let 并在where 子句中进行逻辑连接):

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()
    ;

【讨论】:

  • 我无法设置关系 b/c 它没有在数据库中设置,我也无法触及。如果我在模型中设置它,那么当模型更新时,它将被覆盖,其他开发人员将不知道/不记得每次都将其添加回来。
  • @RememberME:那么,你对哪一部分有问题?如果您对其进行编辑以适应该问题并进行显式联接,则该查询仍然应该有效。
  • 如何将连接添加到其中?我不能加入一个让。
  • @RememberME:您可以使用 where 子句隐式添加连接。编辑答案以显示这一点。如果它有效,我不知道性能是什么样的。您可能想针对您的数据库尝试LinqPad 之类的操作,以查看它生成的 SQL,并与您的 DBA 交谈以确保查询性能不会太糟糕。
  • 它需要我将 .First() 更改为 .FirstOrDefault()。然后选择所有 c 为 null 的项目。
【解决方案2】:

听起来您正在尝试提出以下查询:

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

我不完全确定如何将其转换为 LINQ,但这是我的最佳尝试:

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();

上面的 LINQ 甚至可能无法编译,但希望它会引导您朝着正确的方向前进。

【讨论】:

  • LINQ 中需要 ==,而不是 =。
  • 哈哈哈哈,哎呀,太尴尬了。我一直在写c#和SQL——我昨晚一定是在SQL模式下。 :) 谢谢!
【解决方案3】:

对不起,我不会说你的语言。但是,例如,在 MySql 中,您可以添加 sort by update_dt DESC LIMIT 1 您可以这样做或类似的吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多