【问题标题】:Linq to SQL Expression Properties That are Translatable to SQL可转换为 SQL 的 Linq to SQL 表达式属性
【发布时间】:2011-12-11 20:03:51
【问题描述】:

我有一个 LINQ to SQL 类,我们将其命名为 Test,我希望能够使用 LINQ 查询访问属性,但我得到了著名的“不支持 SQL 转换”运行时错误。我对概念问题感兴趣。这是我的简化课程:

public class Test
{ 
  public int ID {get; set;} // Stored in Database
  public int NonForeignKeyValue {get; set;} // Stored in Database
}

这是我想要完成的一个示例,但我不希望总是在 LINQ 中显式编写连接的开销:

var db = (new DataContext()).GetTable<Test>();
var q = (from t in db.GetTable<Test>()
         join o in db.GetTable<OtherTable>() on o.ID equals t.ID
         where t.OtherStuff
         select t)

我希望能够向Test 添加一个属性,告诉我OtherTable 中是否有可以与Test 连接的行:

  public bool IsInOtherTable
  {
    get
    {
       return (new DataContext())
              .GetTable<OtherTabke>()
              .Any(x => x.NonForeignKeyValue == this.NonForeignKeyValue));
    }
  }

最终这就是我希望我的代码看起来的样子,但它出错了。我基本上想返回所有包含一些数据库计算值的条目:

using (DataContext db =  new DataContext())
{
   var q = db.GetTable<Test>()
             .Where(x => x.IsInOtherTable && x.OtherStuff); //Error
}       

每次我想检查 Test 是否在另一个表中具有某些信息时,我基本上都在尝试避免编写此代码。我对我描述的确切问题不感兴趣,我更感兴趣的是如何在概念上将连接部分添加到 SQL 并仍然使用 LINQ。我猜我使用的是 Linq.Expression,但我真的不知道,也不知道该怎么做。

顺便说一句,我可以只编写实际的 SQL,因为它并不复杂,但我想知道如何解决这个问题并仍然使用 LINQ。

编辑:我试过这个属性,但我得到了同样的错误。只是将返回类型更改为表达式更复杂...

public System.Linq.Expressions.Expression<Func<Article3, bool>> Exists
{
    get
    {
       using (DataContext db =  new DataContext())
       {
         return i => db.GetTable<OtherTable>()
                       .Any(x => x.NonForeignKeyValue == i.NonForeignKeyValue));
       }
    }
}        

【问题讨论】:

  • 对于初学者,您要一起使用的所有查询都必须使用相同的数据上下文
  • 嵌套 using(...) 块是否折叠成一个 using(...) 块?它是如何工作的?

标签: c# linq linq-to-sql


【解决方案1】:

每次 linq 生成器将代码转换为查询时,它都必须处理一个表达式树。

在您的示例中,您不是在传递表达式,而是传递 - 属性、委托,即表达式访问者无法“进入”的东西。

一般来说,请尝试重新考虑您的条件,以便您拥有Expression&lt;T, bool&gt; 等而不是bool

http://netpl.blogspot.com/2008/02/linq-to-object-vs-linq-to-sql-and.html

【讨论】:

  • 您的链接包含一些关于 Expression 的信息,但它没有解决您想再次访问数据库以获取更多信息的情况...
【解决方案2】:

首先,我认为您可能高估了“始终在 LINQ 中显式编写联接的开销”。这是一行额外的代码,它的优点是可以相对自我记录你正在做什么(总是一件好事),任何其他方法都将首先转换为 SQL,然后转换为查询计划,该计划将至少执行起来一样昂贵,可能更昂贵(SQLServer 是一个很好的连接!)

不过,我可以想到两种选择。

一个是在定义与另一个表的这种关系的类上有一个EntityRef 属性。然后,您可以在查询中测试它是否为空(或者 EntitySet,如果它位于一对多关系的另一端)。

另一种是定义一个 SQL 函数,它返回一个bit 结果,指示一个 id 是否引用了与另一个表相关或不相关的行。

然后在 DataContext 派生类上定义一个受保护的方法,该方法与 C# 术语中的签名匹配,并有一个 Function attribute 将其映射到该 SQL 函数。 (由于这不是您可以在 C# 版本中提供合理的不使用 db 的版本,因此您可以通过调用 ExecuteMethodCall 来实现 C# 函数。

那么你可以使用那个方法来代替join。

不过,这在代码中可能不太容易解释,并且可能比仅保持连接效率低。

【讨论】:

  • 谢谢。我将尝试走 EntityRef 路线。我的目标是尽可能多地抽象出复杂性,因为我使用的是高度规范化的模式。我基本上是在尝试实现功能,然后如果(更像是何时)存在性能问题,我可以解决它们。这可能会落入后面需要解决的问题中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 2011-10-24
  • 1970-01-01
  • 2010-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多