为什么LINQ to SQL在Select中省略列

时间:2013-08-14 21:26:47

标签: linq-to-sql

我正在使用LINQ to SQL来选择记录。我需要将两个查询结合在一起,但是select语句正在被更改,因此表达式不再匹配阻止联合。

此LINQ查询从最终结果中省略了强制列'resultType'和'imageFile'。

var taglist = from t in dc.ProductTags
 where t.Tag.StartsWith(prefixText)
 select new AutoSearch { 
      resultType = "Tag", 
      name = t.Tag, 
      imageFile = string.Empty, 
      urlElement = t.Tag };

这是显示的查询。

{SELECT [t0].[Tag] AS [name] FROM [dbo].[ProductTag] AS [t0] WHERE [t0].[Tag] LIKE @p0}

这是第二个与初始查询联合的查询。

var brandlist = from b in dc.Businesses
                    join t in dc.Tags on b.BusinessId equals t.BusinessId
                    where b.Name.StartsWith(prefixText)
                    where b.IsActive == true
                    where t.IsActive == true
                        select new AutoSearch
                        { 
                        resultType = "Business", 
                        name = b.Name, 
                        imageFile = t.AdImage, 
                        urlElement = b.BusinessId.ToString() };

这是第二个查询的sql。

SELECT [t0].[Name] AS [name], [t1].[AdImage] AS [imageFile], CONVERT(NVarChar(MAX) [t0].[BusinessId]) AS [urlElement] FROM [dbo].[Business] AS [t0] INNER JOIN [dbo].[Tag] AS [t1] ON ([t0].[BusinessId]) = [t1].[BusinessId] WHERE ([t0].[Name] LIKE @p0)

工会......抛出错误。

var unionedResults = taglist.Union(brandlist);

抛出错误。

  

使用UNION,INTERSECT或EXCEPT运算符组合的所有查询在其目标列表中必须具有相同数量的表达式。

这是AutoSearch类。

    public class AutoSearch
    {
    public string name { get; set; }
    public string imageFile { get; set; }
    public string resultType { get; set; }
    public string urlElement { get; set; }
    }

关于将要发生什么的建议???

UPDATE ***

找到了解决方法......

发现了这个问题。

这是LINQ中的一个已知错误,在SO上发现的几个讨论指出了我正确的方向。事实证明,网站上列出的大多数工作都不再有效,因为版本4.0也打破了它们。我找到了另一个有用的工作..

LINQ省略了重复值以进行优化。我能够通过将它们转换为字符串或小写或连接它们来更改丢弃字段的值。

非常低效,但它确实有效。在这一天我失去了一整天,也许它会节省其他时间。

            var taglist = from t in dc.ProductTags
                      where t.Tag.StartsWith(prefixText)
                      let resultType = "Tag"
                      select new AutoSearch() {
                          resultType = resultType, 
                          name = t.Tag,
                          imageFile = t.Tag.ToString(),
                          urlElement = t.Tag.ToLower()
                      };

        var brandlist = from b in dc.Businesses
                    join t in dc.Tags on b.BusinessId equals t.BusinessId
                    where b.Name.StartsWith(prefixText)
                    where b.IsActive == true
                        where t.IsActive == true
                        where t.AdImage != null
                        where t.AdImage != String.Empty
                        let resultType = "Business"
                        select new AutoSearch
                        {
                            resultType = resultType, 
                            name = b.Name, 
                            imageFile = t.AdImage, 
                            urlElement = b.BusinessId.ToString()
                        };

1 个答案:

答案 0 :(得分:1)

当您执行查询的select部分时,您引用的唯一属性是Tag,Linq to Sql知道这一点,并优化查询以仅选择您引用的列。

换句话说,查询的这一部分仅引用“Tag”属性,该属性与数据库中的Tag列相关联。

new AutoSearch { 
  resultType = "Tag", 
  name = t.Tag, 
  imageFile = string.Empty, 
  urlElement = t.Tag };

Linq在这种情况下所做的是将表达式传递给底层提供者(非常类似于二叉树数据结构)。然后,提供程序解析此树并在运行时从中创建SQL查询。优化由提供程序在运行时完成,从而产生您正在查看的SQL查询。

<强>更新

对于union的第二个问题,你基本上试图将两个不同的SQL语句联合起来,这会引起union错误。所以我们来看看。

导致错误的结果语句看起来像这样

SELECT [t0].[Tag] AS [name] FROM [dbo].[ProductTag] AS [t0] WHERE [t0].[Tag] LIKE @p0
UNION
SELECT [t0].[Name] AS [name], [t1].[AdImage] AS [imageFile], CONVERT(NVarChar(MAX) [t0].[BusinessId]) AS [urlElement] FROM [dbo].[Business] AS [t0] INNER JOIN [dbo].[Tag] AS [t1] ON ([t0].[BusinessId]) = [t1].[BusinessId] WHERE ([t0].[Name] LIKE @p0)

显然这是一个问号,因为两者之间的列数不同,并且不会与SQL一起使用。虽然我没有纯粹的linq解决方案,但有一种解决方法。

首先您需要创建一个只返回发送给它的字符串的SQL函数。

CREATE FUNCTION ReturnString( @string varchar(max) )
RETURNS varchar(max)
AS
BEGIN
    RETURN @string
END
GO

接下来将这个新的SQL函数拖放到dbml文件中,最后在查询中只需调用适当的方法。

var taglist = from t in dc.ProductTags
                where t.Tag.StartsWith(prefixText)
                select new AutoSearch
                {
                    resultType = dc.ReturnString("Tag"),
                    name = t.Tag,
                    imageFile = dc.ReturnString(string.Empty),
                    urlElement = dc.ReturnString(t.Tag)
                };

var brandlist = from b in dc.Businesses
                join t in dc.Tags on b.BusinessId equals t.BusinessId
                where b.Name.StartsWith(prefixText)
                where b.IsActive == true
                where t.IsActive == true
                select new AutoSearch
                {
                    resultType = dc.ReturnString("Business"),
                    name = b.Name,
                    imageFile = t.AdImage,
                    urlElement = b.BusinessId.ToString()
                };

现在你应该可以执行联合了。