如何使用LINQ返回记录列表以及最新的相关记录

时间:2013-09-02 13:10:54

标签: sql linq

我是LINQ的新手,我正在努力寻找如何做到这一点。

我有一个具有sql server后端的系统,它使用EF5与数据库进行交互。我有以下表格

Case 
CaseStatus
Status
CaseAction
ActionType

关系是......

Case (1 - many) CaseStatus
CaseStatus (1 - many) CaseAction
Status (1 - many) CaseStatus
ActionType (1 - many) CaseAction

我需要显示一个案例记录列表,其中包括最新状态(基于与案例相关的最后一个CaseStatus记录)和最新的Action记录(基于与最新CaseStatus记录相关的最新CaseAction记录)情况下)

所有案例至少都有CaseStatus记录,但并非所有CaseStatus记录都有相关的CaseAction记录。在这些场景中,我仍然需要显示Case记录中的一些细节,但我将Action列留空

在T-SQL中,这种东西会给我我想要的东西

select 
    c.ID            CaseID
    ,cs1.Name       CurrentStatus
    ,cs1.Date       StatusDate
    ,ca1.Name       LatestAction
    ,ca1.Date       ActionDate

from 
    [Case] c
    left join 
    --Latest CaseStatus record to get current status of case
    (
    select
        cs.ID
        ,cs.CaseID
        ,s.Name 
        ,cs.Date
        ,ROW_NUMBER() over (partition by caseid order by cs.id desc) rn
    from
        CaseStatus cs
        --Join to status to get the name of the statusID
        inner join Status s on cs.StatusID=s.ID

    )   cs1
    on c.ID=cs1.CaseID and cs1.rn=1


left join 
    --Latest CaseAction on the case
    (
    select
        ca.CaseStatusID
        ,at.Name    
        ,ca.Date
        ,ROW_NUMBER() over (partition by casestatusID order by ca.id desc) rn
    from
        CaseAction ca
        inner join ActionType at on ca.ActionTypeID=at.ID

    ) ca1
    on ca1.CaseStatusID=cs1.ID and ca1.rn=1

我知道我可以做的一件事就是将我的数据放入我的应用程序中,在我的EF模型中包含包含此SQL的视图。

我想要的是,为了学习的目的,能够使用LINQ获得相同的结果。如果可能的话,我真的希望看到使用综合语法和扩展方法语法的例子

提前感谢您的任何帮助

3 个答案:

答案 0 :(得分:1)

我假设你有一个Case类,它具有Statuses属性,它是CaseStatus个对象的集合。此外,CaseStatus对象具有Status属性和一组名为Actions的CaseAction对象。我还假设您有一个名为DbContext的{​​{1}} - 后代实体,您可以通过该实体访问数据。

在这种情况下,查询相对简单:

context

答案 1 :(得分:0)

据我所知,linq中没有等效的ROW_NUMBER。

您需要在linq中使用几个groupjoin来实现相同的结果。 Groupjoin与DefaultIfEmpty相结合等同于SQL中的左连接(并在原始SQL中以相​​同方式发送)请参阅http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx上的Microsoft示例

因此,在综合语法中,它将是:

var q = from c in db.Cases
        join cs1 in 
        (  
            from cs in db.CaseStatus.OrderByDescending(x => x.ID)
            join s in db.Status on cs.StatusId equals s.ID
            join ca1 in
            (
              from ca in db.CaseAction.OrderByDescending(x => x.ID)
              join a in db.Action on ca.ActionId equals a.ID
              select new {ca, ActionName = a.Name} 
            )
            on cs.ID equals ca1.ca.CaseStatusID
            into caGrp
            from caDft in caGrp.FirstOrDefault()
            select new {cs, 
                        StatusName = s.Name, 
                        LastActionName = (caDft==null? String.Empty : caDft.ActionName)
                        LastActionDate = (caDft==null? String.Empty : caDft.ca.Date)
                       }
        ) on c.ID equals cs1.cs.CaseId
        into csGrp
        from csDft in csGrp.First()
        select new {c, csDft};
 return q.ToList().Select(x => new{
                                   CaseID = x.c.ID, 
                                   StatusName = x.csDft.StatusName,
                                   StatusDate = x.csDft.cs.Date,
                                   ActionName = x.csDft.LastActionName,
                                   ActionDate = x.csDft.LastActionDate
                                  });

注意 - 它不是非常纯粹的综合linq,因为我使用了OrderByDescending扩展方法,但足够接近;)我将扩展方法版本留给其他人

答案 2 :(得分:0)

我设法提出以下似乎给了我所需要的东西。感谢指点家伙

var cases = db.Cases
    .Select(c => new
        {
            CaseID = c.ID,
            LatestStatus = c.CaseStatus
                    .Where(cs => cs.CaseID == c.ID)
                    .OrderByDescending(cs => cs.ID)
                    .FirstOrDefault()
        })
        .Select(c => new
            {
                CaseID = c.CaseID,
                CurrentStatus = c.LatestStatus.Status.Name,
                LatestAction = c.LatestStatus.CaseActions
                            .Where(ca => ca.CaseStatusID == c.LatestStatus.ID)
                            .OrderByDescending(ca => ca.ID)
                            .FirstOrDefault()
        })
        .Select(c => new CaseListItem
                        {
                            CaseID = c.CaseID,
                            CurrentStatus = c.CurrentStatus,
                            LastAction = c.LatestAction != null ? c.LatestAction.ActionType.Name : "-",
                            ActionDate = c.LatestAction != null ? c.LatestAction.Date : null
                        });