Page 1 of 1

CompiledQuery problem with parameter

Posted: Mon 15 Mar 2010 11:08
by crazypit
Hello,

I try to pass to a CompiledQuery.Compile method a parameter of type IQueryable in order to use it with the inner query and join with it. The parameter is the result of an other CompiledQuery.Compile method:

public partial class Udf
{
public static Func> ClientsService_GetUdfsByRefType =
CompiledQuery.Compile(
(ExrayDataContext dataContext, long RefTypeId, string refType) =>
(from objUdf in dataContext.Udfs
from objGroupAssoc in dataContext.UdfsGroups
from objGroup in dataContext.Udfgroups
where objGroup.SubType_Str == UdfGroupSubTypeEnum.CustManagMain.ToString("d") &&
objGroup.Type_Str == UdfGroupTypeEnum.ClientView.ToString("d") &&
objGroup.UdfType_Str == UdfGroupUdfTypeEnum.Customer.ToString("d") &&
objGroupAssoc.UdfgroupId == objGroup.Id &&
objUdf.Id == objGroupAssoc.UdfId &&
(objUdf.RefTypeId == RefTypeId || objUdf.RefTypeId == null) &&
objUdf.RefType_Str == refType &&
objUdf.Status_Str == ActivationStatusEnum.Active.ToString("d") &&
objUdf.AccessType_Str != UDFAccessTypeEnum.Internal.ToString("d")
select objUdf));


public static Func, IQueryable>
ClientsService_GetUdfsByRefType_2 =
CompiledQuery.Compile(
(ExrayDataContext dataContext, IQueryable queryUdfs) =>
from objDefaultValue in dataContext.UdfsDefaultValues
from objUdf in queryUdfs
where objUdf.Id == objDefaultValue.UdfId
select objDefaultValue);
}


If i try to run this:

var defaultValuesList =
Udf.ClientsService_GetUdfsByRefType_2(dataContext,
Udf.ClientsService_GetUdfsByRefType(dataContext, RefTypeId, refType.ToString("d"))).
ToList();

I get a "Parameters cannot be sequences." exception with the following stack trace:

at Devart.Data.Linq.Provider.Query.bk.a(SqlNode A_0)
at Devart.Data.Linq.Provider.Query.bk.a(Expression A_0)
at Devart.Data.Linq.Provider.Query.bk.a(Expression A_0, Expression A_1, Expression A_2)
at Devart.Data.Linq.Provider.Query.bk.b(MethodCallExpression A_0)
at Devart.Data.Linq.Provider.Query.bk.j(Expression A_0)
at Devart.Data.Linq.Provider.Query.bk.a(Expression A_0)
at Devart.Data.Linq.Provider.Query.bk.a(Expression A_0, LambdaExpression A_1)
at Devart.Data.Linq.Provider.Query.bk.b(MethodCallExpression A_0)
at Devart.Data.Linq.Provider.Query.bk.j(Expression A_0)
at Devart.Data.Linq.Provider.Query.bk.a(Expression A_0)
at Devart.Data.Linq.Provider.Query.bk.d(Expression A_0, Expression A_1)
at Devart.Data.Linq.Provider.Query.bk.b(MethodCallExpression A_0)
at Devart.Data.Linq.Provider.Query.bk.j(Expression A_0)
at Devart.Data.Linq.Provider.Query.bk.a(LambdaExpression A_0)
at Devart.Data.Linq.Provider.Query.bk.j(Expression A_0)
at Devart.Data.Linq.Provider.Query.bk.i(Expression A_0)
at Devart.Data.Linq.Provider.DataProvider.a(Expression A_0)
at Devart.Data.Linq.Provider.DataProvider.i(Expression A_0)
at Devart.Data.Linq.CompiledQuery.a(e A_0)
at Devart.Data.Linq.CompiledQuery.a(DataContext A_0, Object[] A_1)
at Devart.Data.Linq.CompiledQuery.Invoke[a,b,c](a A_0, b A_1)

Posted: Mon 15 Mar 2010 11:13
by crazypit
This is a very serious limitation. Imagine all the cases where a "Where" clause is incrementally built according to parameters. If we cannot compile each query and then pass it as a parameter to the next, a large amount of complex queries are left outside the performance gain of pre-compilation.

Posted: Tue 16 Mar 2010 13:51
by AndreyR
Unfortunately, we are unable to provide support for this scenario. The reason is the fact that any query can be
passed as a parameter instead of IQueryable (possibly not the one you have written).
So there is no possibility to compile a query with unknown text.

Posted: Tue 16 Mar 2010 15:09
by crazypit
I'm not talking about the classic kind of parameter and my example do not give the correct meaning of what i'm trying to do...

Obviously, the compiled query means that the SQL is generated and therefore we cannot pass an IQueryable as a parameter, because it will change the final SQL.

What i'm talking about is a way to provide the IQueryable to be compiled not in compile time, but in runtime.

The input of a CompiledQuery is essentially an IQueryable object. There can be parameters as long as they don't change the shape of the final expression. That is all. So, why does the developer has to provide the IQueryable at design time only and not be able to provide it at runtime using some logic? The first time the IQueryable is provided, it should be compiled and this is the one to be used whenever the delegate is called.

Posted: Wed 17 Mar 2010 15:56
by AndreyR
The problem is in IQueryable in the parameter list of CompiledQuery.Compile(). It can be modified and that's the reason of the problem.
We will investigate the possibility to implement the workaround to implement the scenario you describe, because it is reasonable. I will let you know about the results.

Posted: Mon 29 Mar 2010 07:10
by AndreyR
Unfortunately, we don't have technical possibility to implement any workaround solution at the moment.