我有一个LINQ to SQL类,我们称之为Test
,我希望能够使用LINQ查询访问属性,但我得到了着名的“No Supported Translation to 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。
编辑:我试过这个属性,但是我得到了同样的错误。将返回类型更改为Expression ...
更复杂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));
}
}
}
答案 0 :(得分:1)
每次linq生成器将代码转换为查询时,都必须处理表达式树。
在你的例子中,你没有传递表达式,而是 - 属性,委托,即表达式访问者无法“进入”的东西。
一般情况下,请尝试重新考虑您的条件,以便bool
代替Expression<T, bool>
等。
http://netpl.blogspot.com/2008/02/linq-to-object-vs-linq-to-sql-and.html
答案 1 :(得分:0)
首先,我认为你可能会高估“始终在LINQ中明确编写连接的开销”。这是一个额外的代码行,它具有相对自我记录的优势,就像你正在做的事情一样(总是一件好事),而任何其他方法都将首先转变为SQL,然后转变为一个查询计划。至少执行成本高,可能更昂贵(SQLServer是一个很好的连接!)
尽管如此,我还是可以想到两种选择。
一个是在类上有一个EntityRef属性,用于定义与另一个表的这种关系。然后,您可以测试查询中是否为null(如果它位于一对多关系的另一侧,则为EntitySet
。)
另一种是定义一个返回bit
结果的SQL函数,该结果指示id是否引用与另一个表相关或不相关的行。
然后在DataContext派生类上定义一个与C#术语中的签名匹配的受保护方法,并将Function attribute映射到该SQL函数。 (因为这不是你可以在C#版本中提供合理的非db-using版本的东西,你可以通过调用ExecuteMethodCall来实现C#函数。)
然后您可以使用该方法代替连接。
尽管如此,这在代码中可能不太明显,并且存在效率低于仅仅保持连接的风险。