【问题标题】:The text data type cannot be selected as DISTINCT because it is not comparable文本数据类型不能选择为 DISTINCT,因为它不可比较
【发布时间】:2012-04-21 02:57:30
【问题描述】:

我遇到了问题,因为我正在尝试连接一个旧的第三方数据库并从中检索数据,该数据库使用现已弃用的文本字段。但是,我无法更改数据库字段,因此当我尝试通过 LINQ 返回数据时会出现问题。示例代码如下:

var query = from s in db.tSearches
            join c in db.tCompanies on s.CompanyGUID equals c.GUID
            join cl in db.tCompanyLocations on s.LocationGUID equals cl.GUID
            join st in db.tSearchTypes on s.SearchTypeGUID equals st.GUID
            where s.DateClosed == null                        
            select new
            {
                Id = s.GUID,
                Type = st.GUID,
                Location = cl.LocationName,
                Company = (s.Confidential) ? String.Empty : c.CompanyName,
                DateOpened = s.DateOpened,
                Notes = s.PlacementNotes,
                Closed = s.DateClosed != null
            };

在我最终尝试这样做之前,会对此信息进行更多过滤:

        return query.Select(x => new VacancySummary
        {
            Id = x.Id,
            Departments = "",
            Location = x.Location,
            Company = x.Company,
            DateOpened = x.DateOpened,
            Notes = x.Notes,
            Closed = x.Closed
        }).Distinct().Skip(skip).Take(take);

然后得到上面的异常。我宁愿不必先执行整个 SQL 语句并在运行 Distinct 之前返回结果,因为如果每个用户检索每个搜索的所有记录,服务器带宽会降低性能,这就是为什么只有一部分返回数据。

有什么想法吗?

【问题讨论】:

  • 如果它已被弃用,你为什么不直接拉那个字段?
  • @kh25:你能在那个数据库中创建视图吗?我建议使用text 列在表顶部创建一个视图,除了将text 列转换为varchar(max),然后使用LINQ 从视图中查询。
  • @Cory 不幸的是,现阶段我无法修改数据库。如果我有,我会将字段更改为 varchar。至于作为副本,由于没有对数据库的访问权限,我无法使用相同的解决方案。这是我们无法控制的第三方数据库。
  • 如果你这样做Notes = s.PlacementNotes.ToString();,它会在底层 SQL 调用中足够早地转换它吗?

标签: c# sql-server linq


【解决方案1】:

text 类型是哪些列?

一个想法可能是不要编写Distinct() 以便它在SQL 中执行。您可以将数据查询到一组具体的对象中,然后使用 LINQ to Objects 尝试Distinct()

从您所拥有的开始,将原始查询转换为空缺摘要列表:

var query = (from s in db.tSearches
            join c in db.tCompanies on s.CompanyGUID equals c.GUID
            join cl in db.tCompanyLocations on s.LocationGUID equals cl.GUID
            join st in db.tSearchTypes on s.SearchTypeGUID equals st.GUID
            where s.DateClosed == null                        
            select new VacancySummary()
            {
                Id = s.GUID,
                Departments = string.Empty,
                Type = st.GUID,
                Location = cl.LocationName,
                Company = (s.Confidential) ? String.Empty : c.CompanyName,
                DateOpened = s.DateOpened,
                Notes = s.PlacementNotes,
                Closed = s.DateClosed != null
            }).ToList();

您的query 对象现在将是List<VacancySummary>,而不是IQueryable<anonymous type>。您可能需要在 VacancySummary 类上覆盖 Equals() 才能使 distinct 起作用,但您的回报只是变成:

return query.Distinct().Skip(skip).Take(take);

更新:看起来你必须像 in your other question about the same issue 那样处理这个问题。

更新 2: 听说过实体框架中的模型定义函数吗?查看this article。您可以创建概念函数(例如,知道如何将text 列转换为varchar(max)(即CONVERT(varchar(max), PlacementNotes))的函数)。然后,您可以创建一些代码以在您的 LINQ 查询中使用,这些代码将包含在生成的 SQL 中。不知道它是否适合你,但也许值得一试!

【讨论】:

  • 谢谢@Cory - PlacementNotes 是违规者。我试图阻止在 Skip 和 Take 之前执行 ToList(),因为每个用户将返回的数据量存在巨大差异(这可能会影响客户的费用,因为他们将按金额计费他们返回的数据)。如果这不可能,我会将初始查询分成 2 个单独的查询。
  • @kh25:您可以将 PlacementNotes 完全排除在查询之外,稍后通过 tSearches.GUID (VacancySummary.Id) 进行查找。
  • 如果无法完成对数据库的一击所需的操作,这确实是可行的方法。如果我选择那个解决方案,我稍后会发布详细信息。
  • @kh25:我用另一个建议更新了我的答案;请参阅“更新 2”。
  • 谢谢@Cory - 今天晚些时候我会看看。
【解决方案2】:

不是 linq 用户,但在 tsql 中,我们只需将其转换为可比较的 varchar。尝试使用 ToString() 或 Expression.Convert,如有必要,如果字段很大,例如超过 8000 个字符,则截断该字段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多