如何使用Linq to SQL基于另一个表的前1个id加入?

时间:2013-11-14 21:09:38

标签: c# .net sql linq-to-sql

现在,我收到以下错误:

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.

这是我的疑问:

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 }

获取这些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]

......但看起来应该更像这样:

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]

我尝试使用this.NoteDatas代替issue.NoteDatas并手动应用id过滤器,我尝试选择第一个音符然后取id(反转我在上面输入的内容),我尝试使用Take(int)代替First() ...我只是不知道该怎么做。 LINQ读取比它生成的SQL更直接。

2 个答案:

答案 0 :(得分:0)

由此:

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

你说的是“按CreatedDate排序,从结果中取第一行并检查它是否等于NoteId”。这正确地呈现给了:

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]

所以t2.id对于任何外部[t1].[id]始终相同,但仅取决于[t0].[IssueDetailsId]

示例:

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

答案 1 :(得分:0)

这就是我最终改变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 }