I have spent the afternoon trying to wrap my mind around how to translate the following query into LINQ, but I can't quite get there.
我花了整个下午试图将我的想法转换成如何将以下查询转换为LINQ,但我无法完全实现。
declare @productId int; set @productId = 3212;
select * from InformationData data where productId = @productId and orgId = 1
and exists(
select id from (
select coalesce(id1.id, id2.id, id3.id) as id from (
select productId,attributeId from InformationData where productId = @productId group by productId,attributeId
) id
left outer join InformationData id1 on id1.productId = id.productId and id1.attributeId = id.attributeId and id1.language = 1
left outer join InformationData id2 on id2.productId = id.productId and id2.attributeId = id.attributeId and id2.language = 2
left outer join InformationData id3 on id3.productId = id.productId and id3.attributeId = id.attributeId and id3.language = 0
) row
where row.id = data.id
)
The purpose of the query is to fetch data from a table using 2 fallback languages, so if the data does not exist in language 1, it is fetched in language 2, and if 2 does not exists it is fetched for language 0 which is a global translation.
查询的目的是使用2种后备语言从表中获取数据,因此如果数据在语言1中不存在,则使用语言2获取,如果2不存在,则获取语言0,即全球翻译。
I can get the inner query mostly correct (except from id1.language = 1, I can't seem to get it to join on a member of the table I'm joining to, any ideas?)
我可以得到内部查询大多正确(除了id1.language = 1,我似乎无法加入我加入的表的成员,任何想法?)
This is my code (LINQPad code):
这是我的代码(LINQPad代码):
(
from data in (
from d in InformationData where d.ProductId == 3212 group d by new { d.ProductId, d.AttributeId } into p select new { ProductId = p.Key.ProductId, AttributeId = p.Key.AttributeId }
)
join x1 in InformationData on new { a = data.ProductId, b = data.AttributeId } equals new { a = x1.ProductId, b = x1.AttributeId } into f1
from r1 in f1.DefaultIfEmpty()
where r1.Language == 1
join x2 in InformationData on new { a = data.ProductId, b = data.AttributeId } equals new { a = x2.ProductId, b = x2.AttributeId } into f2
from r2 in f2.DefaultIfEmpty()
where r2.Language == 2
join x3 in InformationData on new { a = data.ProductId, b = data.AttributeId } equals new { a = x3.ProductId, b = x3.AttributeId } into f3
from r3 in f3.DefaultIfEmpty()
where r3.Language == 2
select new { Id = ((int?)r1.Id) ?? ((int?)r2.Id) ?? r3.Id }
).Dump();
Which generates the following SQL:
哪个生成以下SQL:
-- Region Parameters
DECLARE @p0 Int SET @p0 = 3212
DECLARE @p1 Int SET @p1 = 2
DECLARE @p2 Int SET @p2 = 2
DECLARE @p3 Int SET @p3 = 1
-- EndRegion
SELECT COALESCE([t2].[id],COALESCE([t3].[id],[t4].[id])) AS [Id]
FROM (
SELECT [t0].[productId], [t0].[attributeId]
FROM [InformationData] AS [t0]
WHERE [t0].[productId] = @p0
GROUP BY [t0].[productId], [t0].[attributeId]
) AS [t1]
LEFT OUTER JOIN [InformationData] AS [t2] ON ([t1].[productId] = [t2].[productId]) AND ([t1].[attributeId] = [t2].[attributeId])
LEFT OUTER JOIN [InformationData] AS [t3] ON ([t1].[productId] = [t3].[productId]) AND ([t1].[attributeId] = [t3].[attributeId])
LEFT OUTER JOIN [InformationData] AS [t4] ON ([t1].[productId] = [t4].[productId]) AND ([t1].[attributeId] = [t4].[attributeId])
WHERE ([t4].[language] = @p1) AND ([t3].[language] = @p2) AND ([t2].[language] = @p3)
But I can't put this together with the rest of the query, maybe I'm just tired buy I keep getting it to do a lot of CROSS APPLY's. Does anyone have any suggestions?
但是我不能把这个与其余的查询结合在一起,也许我只是累了买我继续让它做很多CROSS APPLY的。有没有人有什么建议?
2 个解决方案
#1
Well after a good nights sleep and some crunching things got a bit brighter and I found the solution :) For anyone that is curious here it is
好好睡了一晚,一些嘎吱嘎吱的东西变得更亮了,我找到了解决方案:)对于任何好奇的人来说,这是
(
from i in InformationData
where (
from data in (
from d in InformationData where d.ProductId == 3212 group d by new { d.ProductId, d.AttributeId } into p select new { ProductId = p.Key.ProductId, AttributeId = p.Key.AttributeId }
)
join x1 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 1} equals new { a = x1.ProductId, b = x1.AttributeId, c = x1.Language } into f1
from r1 in f1.DefaultIfEmpty()
join x2 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 2 } equals new { a = x2.ProductId, b = x2.AttributeId, c = x2.Language } into f2
from r2 in f2.DefaultIfEmpty()
join x3 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 0 } equals new { a = x3.ProductId, b = x3.AttributeId, c = x3.Language } into f3
from r3 in f3.DefaultIfEmpty()
select new { Id = ((int?)r1.Id) ?? ((int?)r2.Id) ?? r3.Id }
).Any(d => d.Id == i.Id)
select i
).Dump();
And here is the generated SQL
这是生成的SQL
-- Region Parameters
DECLARE @p0 Int SET @p0 = 3212
DECLARE @p1 Int SET @p1 = 1
DECLARE @p2 Int SET @p2 = 2
DECLARE @p3 Int SET @p3 = 0
-- EndRegion
SELECT [t0].[id] AS [Id], [t0].[attributeId] AS [AttributeId], [t0].[productId] AS [ProductId], [t0].[value] AS [Value], [t0].[orgId] AS [OrgId], [t0].[version] AS [Version], [t0].[language] AS [Language], [t0].[metaType] AS [MetaType], [t0].[overload] AS [Overload], [t0].[parentId] AS [ParentId]
FROM [InformationData] AS [t0]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT COALESCE([t3].[id],COALESCE([t4].[id],[t5].[id])) AS [value]
FROM (
SELECT [t1].[productId], [t1].[attributeId]
FROM [InformationData] AS [t1]
WHERE [t1].[productId] = @p0
GROUP BY [t1].[productId], [t1].[attributeId]
) AS [t2]
LEFT OUTER JOIN [InformationData] AS [t3] ON ([t2].[productId] = [t3].[productId]) AND ([t2].[attributeId] = [t3].[attributeId]) AND (@p1 = [t3].[language])
LEFT OUTER JOIN [InformationData] AS [t4] ON ([t2].[productId] = [t4].[productId]) AND ([t2].[attributeId] = [t4].[attributeId]) AND (@p2 = [t4].[language])
LEFT OUTER JOIN [InformationData] AS [t5] ON ([t2].[productId] = [t5].[productId]) AND ([t2].[attributeId] = [t5].[attributeId]) AND (@p3 = [t5].[language])
) AS [t6]
WHERE [t6].[value] = [t0].[id]
)
#2
Based mostly on your description of what the query is supposed to do, I think you may be able to accomplish the same result with the appropriate "orderby" clause and retrieving just the first result. Like this:
主要基于您对查询应该执行的操作的描述,我认为您可以使用适当的“orderby”子句完成相同的结果并仅检索第一个结果。像这样:
var result =
(
from d in InformationData
where d.ProductId == 3212
orderby ((d.language == 0) ? Int32.MaxValue : d.language)
select d
).First();
EDIT: You can control the search precedence by extending the orderby clause. For example, if the precedence should be 2, then 3, then 1, then anything else, you could do this:
编辑:您可以通过扩展orderby子句来控制搜索优先级。例如,如果优先级应该是2,那么3,然后是1,那么其他任何东西,你可以这样做:
var result =
(
from d in InformationData
where d.ProductId == 3212
orderby
(d.language == 2) ? 0
: (d.language == 3) ? 1
: (d.language == 1) ? 2
: Int32.MaxValue
select d
).First();
#1
Well after a good nights sleep and some crunching things got a bit brighter and I found the solution :) For anyone that is curious here it is
好好睡了一晚,一些嘎吱嘎吱的东西变得更亮了,我找到了解决方案:)对于任何好奇的人来说,这是
(
from i in InformationData
where (
from data in (
from d in InformationData where d.ProductId == 3212 group d by new { d.ProductId, d.AttributeId } into p select new { ProductId = p.Key.ProductId, AttributeId = p.Key.AttributeId }
)
join x1 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 1} equals new { a = x1.ProductId, b = x1.AttributeId, c = x1.Language } into f1
from r1 in f1.DefaultIfEmpty()
join x2 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 2 } equals new { a = x2.ProductId, b = x2.AttributeId, c = x2.Language } into f2
from r2 in f2.DefaultIfEmpty()
join x3 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 0 } equals new { a = x3.ProductId, b = x3.AttributeId, c = x3.Language } into f3
from r3 in f3.DefaultIfEmpty()
select new { Id = ((int?)r1.Id) ?? ((int?)r2.Id) ?? r3.Id }
).Any(d => d.Id == i.Id)
select i
).Dump();
And here is the generated SQL
这是生成的SQL
-- Region Parameters
DECLARE @p0 Int SET @p0 = 3212
DECLARE @p1 Int SET @p1 = 1
DECLARE @p2 Int SET @p2 = 2
DECLARE @p3 Int SET @p3 = 0
-- EndRegion
SELECT [t0].[id] AS [Id], [t0].[attributeId] AS [AttributeId], [t0].[productId] AS [ProductId], [t0].[value] AS [Value], [t0].[orgId] AS [OrgId], [t0].[version] AS [Version], [t0].[language] AS [Language], [t0].[metaType] AS [MetaType], [t0].[overload] AS [Overload], [t0].[parentId] AS [ParentId]
FROM [InformationData] AS [t0]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT COALESCE([t3].[id],COALESCE([t4].[id],[t5].[id])) AS [value]
FROM (
SELECT [t1].[productId], [t1].[attributeId]
FROM [InformationData] AS [t1]
WHERE [t1].[productId] = @p0
GROUP BY [t1].[productId], [t1].[attributeId]
) AS [t2]
LEFT OUTER JOIN [InformationData] AS [t3] ON ([t2].[productId] = [t3].[productId]) AND ([t2].[attributeId] = [t3].[attributeId]) AND (@p1 = [t3].[language])
LEFT OUTER JOIN [InformationData] AS [t4] ON ([t2].[productId] = [t4].[productId]) AND ([t2].[attributeId] = [t4].[attributeId]) AND (@p2 = [t4].[language])
LEFT OUTER JOIN [InformationData] AS [t5] ON ([t2].[productId] = [t5].[productId]) AND ([t2].[attributeId] = [t5].[attributeId]) AND (@p3 = [t5].[language])
) AS [t6]
WHERE [t6].[value] = [t0].[id]
)
#2
Based mostly on your description of what the query is supposed to do, I think you may be able to accomplish the same result with the appropriate "orderby" clause and retrieving just the first result. Like this:
主要基于您对查询应该执行的操作的描述,我认为您可以使用适当的“orderby”子句完成相同的结果并仅检索第一个结果。像这样:
var result =
(
from d in InformationData
where d.ProductId == 3212
orderby ((d.language == 0) ? Int32.MaxValue : d.language)
select d
).First();
EDIT: You can control the search precedence by extending the orderby clause. For example, if the precedence should be 2, then 3, then 1, then anything else, you could do this:
编辑:您可以通过扩展orderby子句来控制搜索优先级。例如,如果优先级应该是2,那么3,然后是1,那么其他任何东西,你可以这样做:
var result =
(
from d in InformationData
where d.ProductId == 3212
orderby
(d.language == 2) ? 0
: (d.language == 3) ? 1
: (d.language == 1) ? 2
: Int32.MaxValue
select d
).First();