MVC3項目,使用LINQ to Entity和Entity Framework 4 Code-First。LINQ生成不正確的SQL(引用不存在的表)
在另一篇文章(Return products which belong to all tags in a list using LINQ)中,我收到了創建LINQ語句以返回數據子集的幫助。
LINQ在語法上是正確的並且編譯,但生成不正確的SQL。具體來說,它引用了一個不存在的表。如果我更正表名,它會返回正確的數據,所以LINQ似乎是正確的。
注意在保持這種長期職位從得到甚至更長的利益,我不會發布對象類(產品,標籤和ProductTag),但他們在我的前面的問題這裏列出:Return products which belong to all tags in a list using LINQ
的LINQ:
var tags = "administration+commerce"
var tagParams = tags.Split('+').ToList(); //used in linq statement below
_repository.Products.Where(p => tagParams.All(tag => p.Tags.Select(x => x.Name).Contains(tag))).Distinct().Take(75).ToList();
以下是不正確的,正確的SQL代碼。
不正確的SQL使得引用不存在的表
[dbo].[TagProduct]
以及畸形場
[ExtentN].[Tag_TagId]
如果我糾正這些爲 「[DBO]。[ProductTag]」 和「 [ExtentN]。[TagId]「,SQL正確執行並返回正確的數據。
的LINQ生成(和故障)SQL
SELECT
[Extent1].[ProductId] AS [ProductId],
[Extent1].[Name] AS [Name],
[Extent1].[ShortDescription] AS [ShortDescription],
[Extent1].[LongDescription] AS [LongDescription],
[Extent1].[Price] AS [Price]
FROM [dbo].[Product] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM (SELECT
N'administration' AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable1]
UNION ALL
SELECT
N'commerce' AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable2]) AS [UnionAll1]
WHERE (NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[TagProduct] AS [Extent2]
INNER JOIN [dbo].[Tag] AS [Extent3] ON [Extent3].[TagId] = [Extent2].[Tag_TagId]
WHERE ([Extent1].[ProductId] = [Extent2].[Product_ProductId]) AND ([Extent3].[Name] = [UnionAll1].[C1])
)) OR (CASE WHEN (EXISTS (SELECT
1 AS [C1]
FROM [dbo].[TagProduct] AS [Extent4]
INNER JOIN [dbo].[Tag] AS [Extent5] ON [Extent5].[TagId] = [Extent4].[Tag_TagId]
WHERE ([Extent1].[ProductId] = [Extent4].[Product_ProductId]) AND ([Extent5].[Name] = [UnionAll1].[C1])
)) THEN cast(1 as bit) WHEN (NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[TagProduct] AS [Extent6]
INNER JOIN [dbo].[Tag] AS [Extent7] ON [Extent7].[TagId] = [Extent6].[Tag_TagId]
WHERE ([Extent1].[ProductId] = [Extent6].[Product_ProductId]) AND ([Extent7].[Name] = [UnionAll1].[C1])
)) THEN cast(0 as bit) END IS NULL)
)
校正SQL
SELECT
[Extent1].[ProductId] AS [ProductId],
[Extent1].[Name] AS [Name],
[Extent1].[ShortDescription] AS [ShortDescription],
[Extent1].[LongDescription] AS [LongDescription],
[Extent1].[Price] AS [Price]
FROM [dbo].[Product] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM (SELECT
N'administration' AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable1]
UNION ALL
SELECT
N'commerce' AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable2]) AS [UnionAll1]
WHERE (NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[ProductTag] AS [Extent2]
INNER JOIN [dbo].[Tag] AS [Extent3] ON [Extent3].[TagId] = [Extent2].[TagId]
WHERE ([Extent1].[ProductId] = [Extent2].[ProductId]) AND ([Extent3].[Name] = [UnionAll1].[C1])
)) OR (CASE WHEN (EXISTS (SELECT
1 AS [C1]
FROM [dbo].[ProductTag] AS [Extent4]
INNER JOIN [dbo].[Tag] AS [Extent5] ON [Extent5].[TagId] = [Extent4].[TagId]
WHERE ([Extent1].[ProductId] = [Extent4].[ProductId]) AND ([Extent5].[Name] = [UnionAll1].[C1])
)) THEN cast(1 as bit) WHEN (NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[ProductTag] AS [Extent6]
INNER JOIN [dbo].[Tag] AS [Extent7] ON [Extent7].[TagId] = [Extent6].[TagId]
WHERE ([Extent1].[ProductId] = [Extent6].[ProductId]) AND ([Extent7].[Name] = [UnionAll1].[C1])
)) THEN cast(0 as bit) END IS NULL)
)
再次,在SQL的唯一改變是
[dbo].[TagProduct] changed to [dbo].[ProductTag]
[ExtentN].[Tag_TagId] changed to [ExtentN].[TagId]
注意我確保數據庫沒有名爲dbo.TagProduct的對象,並且在我的代碼中沒有引用存在TagProduct(也沒有)。
在我的LINQ語句中是否有問題,或者這是LINQ錯誤?我可以完全拋棄它,只是創建一個存儲過程,但我寧願找到一個修復。
非常感謝併爲這篇長文章道歉。
EDIT
問題被證明是一個有缺陷的實體模型,並在一個多對多關係的表之間的過度和不必要的導航屬性。 Slauma的詳細答案是瞭解發生了什麼的關鍵。
新的模型如下:
public class Product
{
.
.
//public virtual List<Tag> Tags { get; set; } // <--removed
public virtual List<ProductTag> ProductTags { get; set; }
}
public class ProductTag
{
.
.
public virtual Product Product { get; set; }
public virtual Tag Tag { get; set; }
}
public class Tag
{
.
.
//public virtual List<Product> Products { get; set; } // <--removed
public virtual List<ProductTag> ProductTags { get; set; }
}
恩,這不是HTML ...這是SQL ......聽起來你的模型可能已經過時了你的模式。 – 2012-01-31 20:48:29
看起來像你改變你的模型,而不重新創建數據庫 – BrokenGlass 2012-01-31 20:50:56
你應該改變了錯誤的LINQ查詢到我給你更正的一個[這裏](http://stackoverflow.com/q/9074875/601179)... – gdoron 2012-01-31 20:59:06