测试LINQ到SQL表达式
我正在编写一个通过LINQtoSQL与MS SQL数据库一起工作的应用程序。有时我需要执行过滤,有时我的过滤条件太复杂,无法转换为SQL查询。当我试图使它们可翻译时,我希望我的应用程序至少能工作,尽管有时速度很慢 LINQtoSQL数据模型隐藏在存储库中,我不想为不同的情况提供几个GetAll方法重载,也不想知道在上层使用什么重载。所以我想在存储库中测试我的表达式是否可翻译,如果不是,则对整个数据集执行内存中的查询,而不是在查询实例化时抛出NotSupportedException 这就是我现在拥有的:测试LINQ到SQL表达式,linq,linq-to-sql,linq-expressions,Linq,Linq To Sql,Linq Expressions,我正在编写一个通过LINQtoSQL与MS SQL数据库一起工作的应用程序。有时我需要执行过滤,有时我的过滤条件太复杂,无法转换为SQL查询。当我试图使它们可翻译时,我希望我的应用程序至少能工作,尽管有时速度很慢 LINQtoSQL数据模型隐藏在存储库中,我不想为不同的情况提供几个GetAll方法重载,也不想知道在上层使用什么重载。所以我想在存储库中测试我的表达式是否可翻译,如果不是,则对整个数据集执行内存中的查询,而不是在查询实例化时抛出NotSupportedException 这就是我现在
IQueryable<TEntity> table = GetTable<TEntity>();
IQueryable<TEntity> result;
try
{
result = table.Where(searchExpression);
//this will test our expression
//consuming as little resources as possible (???)
result.FirstOrDefault();
}
catch (NotSupportedException)
{
//trying to perform in-memory search if query could not be constructed
result = table
.AsEnumerable()
.Where(searchExpression.Compile())
.AsQueryable();
}
return result;
IQueryable table=GetTable();
可预测的结果;
尝试
{
结果=表。其中(搜索表达式);
//这将测试我们的表情
//消耗尽可能少的资源(???)
result.FirstOrDefault();
}
捕获(不支持异常)
{
//如果无法构造查询,则尝试执行内存内搜索
结果=表格
.可计算的()
.Where(searchExpression.Compile())
.AsQueryable();
}
返回结果;
searchExpression
是Expression
如您所见,我使用FirstOrDefault
尝试实例化查询,如果无法实例化,则抛出异常。但是,当表达式良好时,它将执行无用的数据库调用。我可以使用Any
,Count
或其他方法,它可能比FirstOrDefault
便宜一点,但我想到的所有方法都会花费大量的时间访问数据库,而我所需要的只是测试我的表达式
在没有实际的数据库调用的情况下,是否有其他方法来说明我的表达式是“好”还是“坏”
更新:
或者,更一般地说,是否有一种方法可以告诉LINQ在构建SQL失败时进行内存查询,这样就根本不需要这种测试机制了?我认为这将解决您的问题:
IQueryable<TEntity> table = GetTable<TEntity>();
IQueryable<TEntity> result;
try
{
return table.Where(searchExpression).ToList();
}
catch (NotSupportedException)
{
//trying to perform in-memory search if query could not be constructed
return table
.AsEnumerable()
.Where(searchExpression.Compile())
.ToList();
}
IQueryable table=GetTable();
可预测的结果;
尝试
{
返回表.Where(searchExpression).ToList();
}
捕获(不支持异常)
{
//如果无法构造查询,则尝试执行内存内搜索
返回表
.可计算的()
.Where(searchExpression.Compile())
.ToList();
}
因此,当表达式转换为有效的SQL时,方法返回。否则,它将捕获异常并在内存中运行查询。这应该是可行的,但如果可以检查特定的searchExpression
是否可以转换,它就不能回答您的问题。我认为这样的事情不存在。而不是
result.FirstOrDefault();
使用它是否足够
string sqlCommand = dataContext.GetCommand(result).CommandText;
?
如果表达式没有生成有效的Sql,这将抛出NotSupportedException,但它实际上没有执行sqlCommand。我认为您在这里有一个设计缺陷:您的存储库不应返回
IQueryable
,而只返回与数据库解耦的集合。当你这么做的时候,你的问题就不存在了。你没看到什么?为什么它让你的问题消失,或者为什么它是一个设计缺陷?为什么它让我的问题消失。我可能同意,将IQueryable
返回给使用者可能是一个缺陷,因为这样一来,消费者就可以使用不受控制的不可翻译表达式运行任意查询,这将导致意外的运行时错误。但我想要的是能够在我的存储库中运行任意查询。方法签名看起来是这样的:GetAll(Expression searchExpression)
,我需要保证无论是谁调用它,无论传递给它的是什么合法表达式,它都会返回经过筛选的项集合,至少在内存中是这样。关于该缺陷:是的,这就是我的意思。关于您的问题:不知何故,我忽略了searchExpression
将只针对一个表进行计算。您能给我举一个不受支持的searchExpression
的例子吗?我假设在使用用户定义的方法时会发生这种情况??用户定义的方法、在分部类中定义的属性等等。我们的想法不是尝试“SQLize”每个表达式——已经有很多表达式了,我现在实际上正在对它们进行SQLize——而是保证返回集合。SQLization可能需要数周的时间,但该站点现在需要启动并运行。不过,在某些方面我们可以承受缓慢的速度,这也将实例化查询,我不希望这种情况发生得那么早。如果我最后数一数这些东西呢?或者检查是否有?我仍然可以从SQL server获取整个数据集。您的方法基本上与我的FirstOrDefault()
相同:直接在存储库中实例化查询并捕获实例化异常。不过,我的更好,因为它不获取整个数据集,而只获取第一条记录。使用Any()
可能更好,因为它只能从SQL server获取true/false,而不是整个结构。@Michael:如果表达式无法转换为SQL,则不会命中任何数据库。因此,如果searchExpression
无法转换为SQL,则try
块中的部分将抛出异常,而不会命中数据库。在任何情况下,你将只有一个数据库命中。我想,这正是我需要的。谢谢