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