Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 将复杂SQL查询转换为LINQ_Mysql_Sql_Asp.net Mvc_Linq - Fatal编程技术网

Mysql 将复杂SQL查询转换为LINQ

Mysql 将复杂SQL查询转换为LINQ,mysql,sql,asp.net-mvc,linq,Mysql,Sql,Asp.net Mvc,Linq,我对SQL有丰富的经验,但对LINQ还是相当陌生的,我正在努力将下面的MySQL查询转换为LINQ。 是否有人可以帮助将以下内容转换为LINQ,以便在具有实体框架的ASP.net MVC项目中使用 SELECT S.Submission_ID, P.Photo_ID, C2.Contract_Name, J.Job_Number, D.Device_Name, A.`Display_Name`, S.Submission_Status,

我对SQL有丰富的经验,但对LINQ还是相当陌生的,我正在努力将下面的MySQL查询转换为LINQ。 是否有人可以帮助将以下内容转换为LINQ,以便在具有实体框架的ASP.net MVC项目中使用

SELECT
    S.Submission_ID,
    P.Photo_ID,
    C2.Contract_Name,
    J.Job_Number,
    D.Device_Name,
    A.`Display_Name`,
    S.Submission_Status,
    S.Submission_JobRef,
    S.Created,
    TRUE
FROM
    Submission S
        LEFT JOIN Job J ON S.`Job_ID` = J.`Job_ID`
        LEFT JOIN Contract C2 ON J.`Contract_ID` = C2.`Contract_ID`
        INNER JOIN Submission_Status SS ON S.`Submission_Status` = SS.`ID`
        INNER JOIN Device D ON S.`Device_ID` = D.`Device_ID`
        INNER JOIN ACTION A ON S.`Action_ID` = A.`Action_ID`
        INNER JOIN (
            SELECT
                MIN(P.Photo_ID) AS Photo_ID,
                P.Submission_ID
            FROM
                Photo P
            GROUP BY
                P.`Submission_ID`) P ON S.`Submission_ID` = P.Submission_ID
WHERE
    S.`Submission_Status` <> 3 AND
    (LOCATE(@Criteria, C2.`Contract_Name`) > 0 OR
    LOCATE(@Criteria, J.`Job_Number`) > 0 OR
    LOCATE(@Criteria, D.`Device_Name`) > 0 OR
    LOCATE(@Criteria, A.`Display_Name`) > 0 OR
    LOCATE(@Criteria, SS.`Value`) > 0 OR
    LOCATE(@Criteria, S.`Submission_JobRef`) > 0)
ORDER BY
    S.`Submission_ID` DESC
如有任何上述帮助或指导,将不胜感激


编辑 为了提供帮助,下面是模型中的类,这些类定义了上述查询中使用的实体。(我省略了一些与问题无关的领域)


这是一段相当复杂的SQL语句,包含一个子选择和左连接与内连接的混合。 一些快速建议:

将其分解为一系列linq语句,从核心对象开始,在后续步骤中添加相关部分。如果您将结果保留为IQueryable,编译器将为您将所有结果放在一起,并将其作为一个查询发送到db(即,直到最后一步才发送ToList()

就我个人而言,我使用两个from和一个where扩展方法进行连接,而不是使用连接操作符。首先,我让你更容易知道你得到的是左连接还是内连接

例如:

FROM Submission S LEFT JOIN Job J ON S.`Job_ID` = J.`Job_ID`
我会这样做(对不起,我是c#所以VB的语法可能不太正确)

因此,联接条件在作业的.Where()中,并且.DefaultIfEmpty()告诉它左联接(本质上,如果联接失败,作业将是默认的)

进一步编辑:

经过实验,我得到了返回结果的代码(正确的结果是另一个问题)。再次为c#语法感到抱歉

显然,您可以在测试中改变标准常量以应用于不同的项目,我选择匹配合同-我假设只有一个表匹配

此查询生成以下SQL,看起来有点古怪,但在功能上与原始SQL非常相似

SELECT 
    [Filter1].[SubmissionId] AS [SubmissionId], 
    [GroupBy1].[A1] AS [C1], 
    [Filter1].[ContractName] AS [ContractName], 
    [Filter1].[JobNumber] AS [JobNumber], 
    [Filter1].[DeviceName] AS [DeviceName], 
    [Filter1].[DisplayName] AS [DisplayName], 
    [Filter1].[SubmissionStatus] AS [SubmissionStatus], 
    [Filter1].[SubmissionJobRef] AS [SubmissionJobRef], 
    [Filter1].[Created] AS [Created], 
    cast(1 as bit) AS [C2]
FROM   
(
    SELECT 
        [Extent1].[SubmissionId] AS [SubmissionId], 
        [Extent1].[SubmissionStatus] AS [SubmissionStatus], 
        [Extent1].[SubmissionJobRef] AS [SubmissionJobRef], 
        [Extent1].[Created] AS [Created], 
        [Extent2].[JobNumber] AS [JobNumber], 
        [Extent3].[ContractName] AS [ContractName], 
        [Extent4].[Value] AS [Value], 
        [Extent5].[DeviceName] AS [DeviceName], 
        [Extent6].[DisplayName] AS [DisplayName]
    FROM      
        [dbo].[Submissions] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Jobs] AS [Extent2] ON [Extent2].[JobId] = [Extent1].[JobId]
        LEFT OUTER JOIN [dbo].[Contracts] AS [Extent3] ON [Extent3].[ContractId] = [Extent2].[ContractId]
        INNER JOIN [dbo].[SubmissionStatus] AS [Extent4] ON [Extent4].[Id] = [Extent1].[SubmissionStatus]
        INNER JOIN [dbo].[Devices] AS [Extent5] ON [Extent5].[DeviceId] = [Extent1].[DeviceId]
        INNER JOIN [dbo].[Actions] AS [Extent6] ON [Extent6].[ActionId] = [Extent1].[ActionId]
    WHERE 
        3 <> [Extent1].[SubmissionStatus] 
) AS [Filter1]

INNER JOIN  (
    SELECT 
        [Extent7].[SubmissionId] AS [K1], 
        MIN([Extent7].[PhotoId]) AS [A1]
    FROM 
        [dbo].[Photos] AS [Extent7]
    GROUP BY 
        [Extent7].[SubmissionId] ) AS [GroupBy1] 
    ON [GroupBy1].[K1] = [Filter1].[SubmissionId]
WHERE 
(
    [Filter1].[ContractName] LIKE @p__linq__0 ESCAPE N'~') OR 
    ([Filter1].[JobNumber] LIKE @p__linq__1 ESCAPE N'~') OR 
    ([Filter1].[DeviceName] LIKE @p__linq__2 ESCAPE N'~') OR 
    ([Filter1].[DisplayName] LIKE @p__linq__3 ESCAPE N'~') OR 
    ([Filter1].[Value] LIKE @p__linq__4 ESCAPE N'~') OR 
    ([Filter1].[SubmissionJobRef] LIKE @p__linq__5 ESCAPE N'~')
)   
选择
[Filter1]。[SubmissionId]作为[SubmissionId],
[GroupBy1][A1]作为[C1],
[Filter1]。[ContractName]作为[ContractName],
[Filter1]。[JobNumber]作为[JobNumber],
[Filter1]。[DeviceName]作为[DeviceName],
[Filter1]。[DisplayName]作为[DisplayName],
[Filter1]。[SubmissionStatus]作为[SubmissionStatus],
[Filter1][SubmissionJobRef]作为[SubmissionJobRef],
[Filter1]。[Created]作为[Created],
按[C2]铸造(1为位)
从…起
(
挑选
[Extent1]。[SubmissionId]作为[SubmissionId],
[Extent1]。[SubmissionStatus]作为[SubmissionStatus],
[Extent1][SubmissionJobRef]作为[SubmissionJobRef],
[Extent1].[Created]作为[Created],
[Extent2]。[JobNumber]作为[JobNumber],
[Extent3]。[ContractName]作为[ContractName],
[Extent4]。[Value]作为[Value],
[Extent5]。[DeviceName]作为[DeviceName],
[Extent6]。[DisplayName]作为[DisplayName]
从…起
[dbo].[Submissions]作为[Extent1]
[Extent2].[JobId]=[Extent1].[JobId]上作为[Extent2]的左外部联接[dbo].[Jobs]
左外联接[dbo].[Contracts]作为[Extent3]在[Extent3].[contracted]=[Extent2].[contracted]上的[Extent3]
在[Extent4].[Id]=[Extent1].[SubmissionStatus]上将[dbo].[SubmissionStatus]作为[Extent4]进行内部联接
将[dbo].[Devices]作为[Extent5].[DeviceId]=[Extent1].[DeviceId]上的[Extent5]进行内部联接
将[dbo].[Actions]作为[Extent6].[ActionId]=[Extent1].[ActionId]上的[Extent6]进行内部联接
哪里
3[扩展1][提交状态]
)AS[Filter1]
内连接(
挑选
[Extent7]。[SubmissionId]作为[K1],
最小值([Extent7][PhotoId])为[A1]
从…起
[dbo].[Photos]作为[Extent7]
分组
[Extent7][SubmissionId])作为[GroupBy1]
在[GroupBy1].[K1]=[Filter1].[SubmissionId]上
哪里
(
[Filter1]。[ContractName]如@p__linq____0 ESCAPE N'~')或
([Filter1].[JobNumber]像@p__linq____1 ESCAPE N'~')或
([Filter1].[DeviceName]如@p_ulinq_u2 ESCAPE N'~)或
([Filter1].[DisplayName]如@p_ulinq_u3 ESCAPE N'~')或
([Filter1].[Value]像@p_ulinq_u4 ESCAPE N'~')或
([Filter1].[SubmissionJobRef]类似于@p_ulinq_u5 ESCAPE N'~)
)   

用一句话回应Dave Johnson的评论-可伸缩性

最近,我试图提高应用程序的性能,我的第一个想法是在John Henry的示例中添加一些复杂性类似的SQL—多连接和过滤器。毕竟,它在我的开发机器上的表现就像火箭一样

这位架构师断然禁止在数据库服务器上使用复杂的SQL,因为有几个拥有100多个用户的大型应用程序与之挂钩。尽管我非常喜欢构建快速的SQL,但我不得不同意。将逻辑转移到使用它的机器上是一种很好的架构

因此,对于我们这些精通声明式SQL的人来说,学习linq翻译技巧非常重要


当然,我前面给出的解决方案无法实现这一点,因为相同的SQL被发送到服务器。但是拥有一个linq等价物是一个可以进一步优化的开始。

在大量搜索和阅读各种文章之后,我放弃了用linq查询语法编写此查询,转而使用方法语法

非常感谢Ackroydd在将复杂SQL转换为LINQ方面提供的建议和支持。当您知道您可以在几分钟内用SQL完成一些事情,但需要使用LINQ实现可伸缩性并与现有代码保持一致时,您可能会感到相当沮丧

以下是我的结论,因为我相信它对其他人会有用:

Dim query As IQueryable(Of Submission)

' Initialise the new query
query = db.Submissions.Include(Function(s) s.Action) _
                              .Include(Function(s) s.Photos) _
                              .Include(Function(s) s.Device) _
                              .Include(Function(s) s.Job) _
                              .Include(Function(s) s.Submission_Status1) _
                              .Include(Function(s) s.Job.Contract) _
                              .Include(Function(s) s.Comments) _
                              .AsNoTracking

' Apply initial filters
query = query.Where(Function(S) Not S.Submission_Status1.ID.Equals(3))

' Apply search criteria if passed
If Not String.IsNullOrEmpty(param.sSearch) Then
    query = query.Where(Function(S) S.Job.Contract.Contract_Name.Contains(param.sSearch) OrElse
                                            S.Job.Job_Number.Contains(param.sSearch) OrElse
                                            S.Device.Device_Name.Contains(param.sSearch) OrElse
                                            S.Action.Display_Name.Contains(param.sSearch) OrElse
                                            S.Submission_Status1.Value.Contains(param.sSearch) OrElse
                                            S.Submission_JobRef.Contains(param.sSearch))
End If

' Order the results
query = query.OrderByDescending(Function(S) S.Submission_ID)

' Paginate the results
query = query.Skip(param.iDisplayStart).Take(param.iDisplayLength)

' Return only the required columns
Dim resultData = query.AsEnumerable.Select(Function(S) New AjaxSubmissionOverview With { _
                                                           .Submission_ID = S.Submission_ID,
                                                           .Photo_ID = S.Photos.First.Photo_ID,
                                                           .Contract_Name = If(IsNothing(S.Job), "", S.Job.Contract.Contract_Name),
                                                           .Job_Number = If(IsNothing(S.Job), "", S.Job.Job_Number),
                                                           .Device_Name = S.Device.Device_Name,
                                                           .Action_Name = S.Action.Display_Name,
                                                           .Submission_Status = S.Submission_Status,
                                                           .Submission_JobRef = S.Submission_JobRef,
                                                           .Latest_Comment = If(S.Comments.Count = 0, "", HtmlHelpers.Truncate(S.Comments.Last.Comment1, 100)),
                                                           .Created = S.Created,
                                                           .CanEdit = bolCanEdit})

首先,你应该试着做点什么…导航属性非常重要,所以请显示实体模型的相关部分。为什么你会接受这样一个有效的查询并希望将其转换为LINQ?我会投票支持你的问题,但级别不够高。我认为,这是一个很好的问题。至少,我花了一段时间才熟练地将SQL翻译成等效的linq,并确定结果
Dim results = from s in db.Submissions
              from j in db.Jobs.Where(j=> j.Job_Id == s.Job_Id).DefaultIfEmpty()
    [TestMethod]
    public void Query()
    {
        const string conStr = "Data Source=(local);Initial Catalog=ComplexSqlToLinq; Integrated Security=True";
        var db = new MyDbContext(conStr);

        const string criteria = "Contract1";

        var minPhotos = from p in db.Photos
                        group p by p.SubmissionId
                        into g
                        select new {SubmissionId = g.Key, PhotoId = g.Min(p=>p.PhotoId)};

        var query = from s in db.Submissions
                    from j in db.Jobs.Where(j => j.JobId == s.JobId).DefaultIfEmpty()
                    from c in db.Contracts.Where(c => c.ContractId == j.ContractId).DefaultIfEmpty()
                    from ss in db.SubmissionStatuses.Where(ss => ss.Id == s.SubmissionStatus)
                    from d in db.Devices.Where(d => d.DeviceId == s.DeviceId)
                    from a in db.Actions.Where(a => a.ActionId == s.ActionId)
                    from p in minPhotos.Where(p => p.SubmissionId == s.SubmissionId)

                    where s.SubmissionStatus != 3 &&
                       ( c.ContractName.Contains(criteria) ||
                         j.JobNumber.Contains(criteria) ||
                         d.DeviceName.Contains(criteria) ||
                         a.DisplayName.Contains(criteria) ||
                         ss.Value.Contains(criteria) ||
                         s.SubmissionJobRef.Contains(criteria))

                    select new
                               {
                                   s.SubmissionId,
                                   p.PhotoId,
                                   c.ContractName,
                                   j.JobNumber,
                                   d.DeviceName,
                                   a.DisplayName,
                                   s.SubmissionStatus,
                                   s.SubmissionJobRef,
                                   s.Created,
                                   SomeBool = true
                               };

        var result = query.ToList();
        Assert.IsTrue(result.Any());
    }
SELECT 
    [Filter1].[SubmissionId] AS [SubmissionId], 
    [GroupBy1].[A1] AS [C1], 
    [Filter1].[ContractName] AS [ContractName], 
    [Filter1].[JobNumber] AS [JobNumber], 
    [Filter1].[DeviceName] AS [DeviceName], 
    [Filter1].[DisplayName] AS [DisplayName], 
    [Filter1].[SubmissionStatus] AS [SubmissionStatus], 
    [Filter1].[SubmissionJobRef] AS [SubmissionJobRef], 
    [Filter1].[Created] AS [Created], 
    cast(1 as bit) AS [C2]
FROM   
(
    SELECT 
        [Extent1].[SubmissionId] AS [SubmissionId], 
        [Extent1].[SubmissionStatus] AS [SubmissionStatus], 
        [Extent1].[SubmissionJobRef] AS [SubmissionJobRef], 
        [Extent1].[Created] AS [Created], 
        [Extent2].[JobNumber] AS [JobNumber], 
        [Extent3].[ContractName] AS [ContractName], 
        [Extent4].[Value] AS [Value], 
        [Extent5].[DeviceName] AS [DeviceName], 
        [Extent6].[DisplayName] AS [DisplayName]
    FROM      
        [dbo].[Submissions] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Jobs] AS [Extent2] ON [Extent2].[JobId] = [Extent1].[JobId]
        LEFT OUTER JOIN [dbo].[Contracts] AS [Extent3] ON [Extent3].[ContractId] = [Extent2].[ContractId]
        INNER JOIN [dbo].[SubmissionStatus] AS [Extent4] ON [Extent4].[Id] = [Extent1].[SubmissionStatus]
        INNER JOIN [dbo].[Devices] AS [Extent5] ON [Extent5].[DeviceId] = [Extent1].[DeviceId]
        INNER JOIN [dbo].[Actions] AS [Extent6] ON [Extent6].[ActionId] = [Extent1].[ActionId]
    WHERE 
        3 <> [Extent1].[SubmissionStatus] 
) AS [Filter1]

INNER JOIN  (
    SELECT 
        [Extent7].[SubmissionId] AS [K1], 
        MIN([Extent7].[PhotoId]) AS [A1]
    FROM 
        [dbo].[Photos] AS [Extent7]
    GROUP BY 
        [Extent7].[SubmissionId] ) AS [GroupBy1] 
    ON [GroupBy1].[K1] = [Filter1].[SubmissionId]
WHERE 
(
    [Filter1].[ContractName] LIKE @p__linq__0 ESCAPE N'~') OR 
    ([Filter1].[JobNumber] LIKE @p__linq__1 ESCAPE N'~') OR 
    ([Filter1].[DeviceName] LIKE @p__linq__2 ESCAPE N'~') OR 
    ([Filter1].[DisplayName] LIKE @p__linq__3 ESCAPE N'~') OR 
    ([Filter1].[Value] LIKE @p__linq__4 ESCAPE N'~') OR 
    ([Filter1].[SubmissionJobRef] LIKE @p__linq__5 ESCAPE N'~')
)   
Dim query As IQueryable(Of Submission)

' Initialise the new query
query = db.Submissions.Include(Function(s) s.Action) _
                              .Include(Function(s) s.Photos) _
                              .Include(Function(s) s.Device) _
                              .Include(Function(s) s.Job) _
                              .Include(Function(s) s.Submission_Status1) _
                              .Include(Function(s) s.Job.Contract) _
                              .Include(Function(s) s.Comments) _
                              .AsNoTracking

' Apply initial filters
query = query.Where(Function(S) Not S.Submission_Status1.ID.Equals(3))

' Apply search criteria if passed
If Not String.IsNullOrEmpty(param.sSearch) Then
    query = query.Where(Function(S) S.Job.Contract.Contract_Name.Contains(param.sSearch) OrElse
                                            S.Job.Job_Number.Contains(param.sSearch) OrElse
                                            S.Device.Device_Name.Contains(param.sSearch) OrElse
                                            S.Action.Display_Name.Contains(param.sSearch) OrElse
                                            S.Submission_Status1.Value.Contains(param.sSearch) OrElse
                                            S.Submission_JobRef.Contains(param.sSearch))
End If

' Order the results
query = query.OrderByDescending(Function(S) S.Submission_ID)

' Paginate the results
query = query.Skip(param.iDisplayStart).Take(param.iDisplayLength)

' Return only the required columns
Dim resultData = query.AsEnumerable.Select(Function(S) New AjaxSubmissionOverview With { _
                                                           .Submission_ID = S.Submission_ID,
                                                           .Photo_ID = S.Photos.First.Photo_ID,
                                                           .Contract_Name = If(IsNothing(S.Job), "", S.Job.Contract.Contract_Name),
                                                           .Job_Number = If(IsNothing(S.Job), "", S.Job.Job_Number),
                                                           .Device_Name = S.Device.Device_Name,
                                                           .Action_Name = S.Action.Display_Name,
                                                           .Submission_Status = S.Submission_Status,
                                                           .Submission_JobRef = S.Submission_JobRef,
                                                           .Latest_Comment = If(S.Comments.Count = 0, "", HtmlHelpers.Truncate(S.Comments.Last.Comment1, 100)),
                                                           .Created = S.Created,
                                                           .CanEdit = bolCanEdit})