【问题标题】:"Cannot call methods on DateTime", and other limitations“不能在 DateTime 上调用方法”和其他限制
【发布时间】:2008-11-27 13:02:18
【问题描述】:

是否有人知道在编译时未捕获的 LINQ to SQL 查询限制的最终列表,以及(在可能的情况下)限制的解决方法?

我们目前的名单是:

  • DateTime上调用.Date等方法
    • 未找到解决方法
  • string.IsNullOrEmpty
    • 简单,用== ""代替
  • .Last()
    • 我们使用.OrderByDescending(x => x.WhateverProperty).First()

【问题讨论】:

  • 这个列表的问题在于它有点像证明否定。你不能做的事情的清单是无限的,你可以做的事情清单要短得多。

标签: .net sql linq linq-to-sql


【解决方案1】:

基本上,该列表很大...它是相对small set of things that are handled 之外的所有内容。不幸的是,Law Of Leaky Abstractions 开始了,每个提供者都有不同的答案...

LINQ-to-Objects 可以做任何事情(几乎),因为它是委托; LINQ-to-SQL 和 Entity Framework 具有不同的组支持。

一般来说,我在使用 DateTime 属性等方面取得了相当大的成功 - 但实际上,您必须确保您的查询表达式被单元测试覆盖,这样如果您曾经更改提供者(或提供者更新)你知道这一切仍然有效。

我想一种观点是从 TSQL 的角度来思考;没有BOTTOM n,但有一个TOP 1(重新OrderByDescending);就string.IsNullOrEmpty 而言,您可以很直白:foo.Bar == null || foo.Bar == "";使用DateTime.Date,您可能可以使用DATEPART / 各种组件做很多事情。

LINQ-to-SQL 的另一个选项是将逻辑封装在 UDF 中 - 因此您可以编写一个接受 datetime 并返回 datetime 的 UDF,并通过 dbml 将其公开到数据上下文中.然后,您可以在查询中使用它:

where ctx.Date(foo.SomeDate) == DateTime.Today

然而,这种方法不一定能很好地利用索引。


更新:

  • 支持的方法翻译等为here
  • 支持的查询操作等为here

有关完整的血腥细节,您可以查看反射器中的System.Data.Linq.SqlClient.PostBindDotNetConverter+Visitor - 特别是Translate... 方法;一些string 函数是单独处理的。所以不是一个 巨大的 选择 - 但这是一个实现细节。

【讨论】:

    【解决方案2】:

    LINQ 是语言。 LINQ-to-SQL 将您的 LINQ 命令编译为 SQL 查询。因此,它受到 TSQL 语法的正常限制,或者更确切地说是可以轻松转换成它的项目的限制。

    正如其他人所说,你不能做的事情的清单将是巨大的。这是您可以做的事情的一个小得多的列表。一般的经验法则是尝试确定您要使用的函数如何转换为 TSQL。如果你很难搞清楚,那就不要使用那个函数(或者至少先测试一下)。

    但有一个简单的解决方法是使用不在 LINQ-to-SQL 中的 LINQ 命令。将代码的纯 LINQ 部分与 LINQ-to-SQL 部分分开。换句话说,使用 LINQ-to-SQL 将数据拉入(使用 LINQ-to_SQL 中提供的任何您需要的函数),并使用命令将其放入对象(ToEnumerable、ToList 或其他类似对象)。这将执行查询并将数据拉到本地。现在它可用于完整的 LINQ 语法。

    【讨论】:

      【解决方案3】:

      我为 String.IsNullOrEmpty() 创建了一个连接问题:

      Feedback: I want to use string.IsNullOrEmpty in LINQ to SQL statements.

      随意添加您的声音或投票,或为在 Linq to SQL 中不起作用的各种其他方法创建其他连接问题。吱吱作响的轮子得到了润滑脂。

      【讨论】:

        【解决方案4】:

        我确实遇到了 DateTimes 的这个问题,并发现目前以下解决方法对我有用,但我意识到对于更大的结果集,它可能会成为一个问题,因为处理现在在我的应用程序中,而不是在数据库:

        BlogPosts post = (from blogs in blogPosts
                   where blogs.PostPath == path 
                   select blogs)
                   .ToList()
                   .Where(blogs => blogs.Published.Date == publishedDate.Date)
                   .SingleOrDefault();
        

        注意中间的“.ToList()” - 这会将其转换为普通的 IEnumerable,并允许我使用我期望的常用属性。

        然而,我仍然有点困惑的一件事是,这在 EF 中是合法的:

        BlogPosts posts = from blogs in blogPosts
                   where !blogs.IsDraft
                     && blogs.Published.Year == year
                     && blogs.Published.Month == month
                   orderby blogs.Published descending
                   select blogs
        

        所以,我可以在 DateTime 上调用“.Year”或“.Month”,但不能调用“.Date”——我想这归结为类型。

        【讨论】:

        • 干杯,我也试试看。
        • .AsEnumerable() 侵入性较小(无缓冲);无论哪种方式,您都会失去可组合性。
        【解决方案5】:

        Marc Gravell 的回答完全正确。

        我只是想为日期逻辑(和字符串比较)添加这个细节。由于您使用的是 LinqToSql,因此您可以利用 SqlMethods 来做您习惯在数据库中做的那些事情。

        【讨论】:

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