简体   繁体   English

如何使用Linq to SQL基于另一个表的前1个id进行联接?

[英]How to join based on the top 1 id of another table using Linq to SQL?

Right now, I receive the following error: 现在,我收到以下错误:

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

This is my query: 这是我的查询:

var issues = from issue in this.IssueDatas
             join original in this.NoteDatas on issue.NoteDatas
                                                     .OrderBy(n => n.CreatedDate)
                                                     .Select(n => n.NoteId)
                                                     .First() equals original.NoteId
             join current in this.NoteDatas on issue.NoteDatas
                                                    .OrderByDescending(n => n.CreatedDate)
                                                    .Select(n => n.NoteId)
                                                    .First() equals current.NoteId
             select { whatever, i, want, to, select }

The SQL portion to grab those TOP 1 ids comes out like this: 抓住那些TOP 1 id的SQL部分如下所示:

SELECT whatever, i, want, to
FROM [dbo].[issue_Details] AS [t0]
INNER JOIN [dbo].[issue_notes] AS [t1] ON ((
    SELECT TOP (1) [t3].[id]
    FROM (
        SELECT [t2].[id], [t2].[issue_id]
        FROM [dbo].[issue_notes] AS [t2]
        ORDER BY [t2].[CreatedDate]
        ) AS [t3]
    WHERE [t3].[issue_id] = [t0].[IssueDetailsId]
    )) = [t1].[id]
INNER JOIN [dbo].[issue_notes] AS [t4] ON ((
    SELECT TOP (1) [t6].[id]
    FROM (
        SELECT [t5].[id], [t5].[issue_id]
        FROM [dbo].[issue_notes] AS [t5]
        ORDER BY [t5].[CreatedDate] DESC
        ) AS [t6]
    WHERE [t6].[issue_id] = [t0].[IssueDetailsId]
    )) = [t4].[id]

...but it should look more like this: ...但是看起来应该更像这样:

FROM [dbo].[issue_Details] AS [t0]
INNER JOIN [dbo].[issue_notes] AS [t1] ON (
    SELECT TOP (1) [t2].[id]
    FROM [dbo].[issue_notes] AS [t2]
    ORDER BY [t2].[CreatedDate]
    WHERE [t2].[issue_id] = [t0].[IssueDetailsId]
    ) = [t1].[id]
INNER JOIN [dbo].[issue_notes] AS [t4] ON (
    SELECT TOP (1) [t5].[id]
    FROM [dbo].[issue_notes] AS [t5]
    ORDER BY [t5].[CreatedDate] DESC
    WHERE [t5].[issue_id] = [t0].[IssueDetailsId]
    ) = [t4].[id]

I've tried using this.NoteDatas instead of issue.NoteDatas and manually applying the id filter, I've tried selecting the first note and then taking the id (reversing what I've typed above), I've tried using Take(int) instead of First() ... I just don't know what to do. 我尝试使用this.NoteDatas而不是issue.NoteDatas并手动应用id过滤器,我尝试选择第一个笔记,然后获取id(与上面输入的内容相反),尝试使用Take(int)而不是First() ...我只是不知道该怎么办。 The LINQ reads more straightforward than the SQL it generates. LINQ读取比生成的SQL更直接。

By this: 这样:

 join original in this.NoteDatas on issue.NoteDatas
                                         .OrderBy(n => n.CreatedDate)
                                         .Select(n => n.NoteId)
                                         .First() equals original.NoteId

you are saying "order by CreatedDate, take first row from the results and check if it equals to NoteId". 您说的是“按CreatedDate排序,从结果中获取第一行,并检查其是否等于NoteId”。 This is correctly gets rendered to this: 正确地渲染到此:

INNER JOIN [dbo].[issue_notes] AS [t1] ON ((
    SELECT TOP (1) [t3].[id]
    FROM (
        SELECT [t2].[id], [t2].[issue_id]
        FROM [dbo].[issue_notes] AS [t2]
        ORDER BY [t2].[CreatedDate]
        ) AS [t3]
    WHERE [t3].[issue_id] = [t0].[IssueDetailsId]
    )) = [t1].[id]

so t2.id is always same for any outer [t1].[id] but depends on only [t0].[IssueDetailsId] 因此,对于任何外部[t1].[id]t2.id始终相同,但仅取决于[t0].[IssueDetailsId]

Sample: 样品:

    var issues = new Tuple<int, string>[]
        {
            new Tuple<int, string>(1, "aaa"),
            new Tuple<int, string>(2, "bbb")
        };
    var notes = new Tuple<int, DateTime, string>[]
        {
            new Tuple<int, DateTime, string>(1, DateTime.Parse("01/01/2001"), "earliest for 1"),
            new Tuple<int, DateTime, string>(1, DateTime.Parse("02/01/2001"), "middle for 1"),
            new Tuple<int, DateTime, string>(1, DateTime.Parse("03/01/2001"), "latest for 1"),
            new Tuple<int, DateTime, string>(2, DateTime.Parse("10/01/2001"), "earliest for 2"),
            new Tuple<int, DateTime, string>(2, DateTime.Parse("11/01/2001"), "middle for 2"),
            new Tuple<int, DateTime, string>(2, DateTime.Parse("12/01/2001"), "once more middle for 2"),
            new Tuple<int, DateTime, string>(2, DateTime.Parse("13/01/2001"), "latest for 2")
        };

        var result =
            ctx.Set<Parent>().Select(i => new
                {
                    i.Id,
                    e = ctx.Set<Child>().Where(c => c.ParentId == i.Id).OrderBy(c => c.Name).FirstOrDefault(),
                    l = ctx.Set<Child>().Where(c => c.ParentId == i.Id).OrderByDescending(c => c.Name).FirstOrDefault()
                });

This is how I ended up changing the LINQ to have it work: 这就是我最终更改LINQ使其工作的方式:

var issues = from issue in this.IssueDatas
             join original in this.NoteDatas on issue.NoteDatas
                                                     .Min(n => n.CreatedDate) equals original.CreatedDate
             join current in this.NoteDatas on issue.NoteDatas
                                                    .Max(n => n.CreatedDate) equals current.CreatedDate
             select { whatever, i, want, to, select }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM