How to use the PredicateExpression

Posts   
 
    
matan86
User
Posts: 4
Joined: 13-Feb-2025
# Posted on: 13-Feb-2025 14:23:58   

Dear all, despite the many threads about the PredicateExpression as well as the documentation, i didn't manage to get rid yet of the below issue.

I'm currently using LLBLGen v5.10, Selfservicing.

There is a table containing approximately 5k rows which needs to be filtered according to some criteria (e.g.: UserId, AttemptId, SubjectId). As not all filter criteria might be filled at the same time (e.g.: there could be only the UserId or UserId+AttemptId or AttemptId), and as I prefer not to retrieve all the 5k items from the database first and then apply the filtering, I thought that the PredicateExpression could be the right stuff. Therefore, I wrote the below code:

      var filter = new SD.LLBLGen.Pro.ORMSupportClasses.PredicateExpression();
      if (userId != Guid.Empty)
      {
        filter.Add(ViewQuizAttemptFields.UserId == userId);
      }

      if (quizSubjectId != Guid.Empty)
      {
        filter.Add(ViewQuizAttemptFields.QuizSubjectId == quizSubjectId);
      }

      if (quizAttemptId != Guid.Empty)
      {
        filter.Add(ViewQuizAttemptFields.QuizAttemptId == quizAttemptId);
      }
      LinqMetaData md = new LinqMetaData();
      List<ViewQuizAttemptEntity> viewQuizAttempt = md.ViewQuizAttempt.Where(filter);

The issue is when I try to pass the "filter" to the "Where" because the compiler says:

'SD.LLBLGen.Pro.LinqSupportClasses.DataSource<xxx.DAL.EntityClasses.ViewQuizAttemptEntity>' cannot be used as type parameter 'TQuery' in the generic type or method 'QuerySpecExtensionMethods.Where<TQuery>(TQuery, IPredicate)'. There is no implicit reference conversion from 'SD.LLBLGen.Pro.LinqSupportClasses.DataSource<xxx.DAL.EntityClasses.ViewQuizAttemptEntity>' to 'SD.LLBLGen.Pro.QuerySpec.QuerySpec'.

Is there anyone who can help me in fixing this error? Perhaps it's me building things in the wrong way... Any help would be appreciated. Thanks.

Walaa avatar
Walaa
Support Team
Posts: 14992
Joined: 21-Aug-2005
# Posted on: 13-Feb-2025 15:36:00   

For LinqtoLLBLGen you need to use PredicateBuilder

or use what was proposed here

matan86
User
Posts: 4
Joined: 13-Feb-2025
# Posted on: 13-Feb-2025 15:40:17   

Thanks, I also came across that thread during my searchings. However, it looks like PredicateBuilder is not exposed at all in any of the two LLBLGenProd DLLs referenced in my project (SD.LLBLGen.Pro.DQE.SqlServer and SD.LLBLGen.Pro.ORMSupportClasses). Do you have any clue what's the dll where it is refrenced?

On the other hand, I think I managed to solve the issue this way even if i'm not fully sure it is the right way.

      ViewQuizAttemptCollection viewQuizAttempt = new ViewQuizAttemptCollection();
      viewQuizAttempt.GetMulti(filter);

Thanks.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 14-Feb-2025 09:12:31   

List<ViewQuizAttemptEntity> viewQuizAttempt = md.ViewQuizAttempt.Where(filter); This will never be valid C# code, as 'Where' is a filter function that returns an IEnumerable<T> or an IQueryable<T>, but never a List<T>. Passing a PredicateExpression to linq methods won't work as they're from a different querying system. Our runtime supports 3 different querying systems: the low level API (using PredicateExpressions etc.), Linq and QuerySpec. QuerySpec is a fluent API over the low level API so you can re-use predicate expressions and the like with that API but Linq is a different querying API with its own syntax.

collection.GetMulti(p) is a way to query the entities associated with the collection (so in your case ViewQuizAttemptEntity instances) using the low level API. The GetMulti() call is perfectly fine to fetch entities like that using predicate expressions.

In QuerySpec, your query would look like this:

var filter = new SD.LLBLGen.Pro.ORMSupportClasses.PredicateExpression();
if (userId != Guid.Empty)
{
    filter.Add(ViewQuizAttemptFields.UserId == userId);
}

if (quizSubjectId != Guid.Empty)
{
    filter.Add(ViewQuizAttemptFields.QuizSubjectId == quizSubjectId);
}

if (quizAttemptId != Guid.Empty)
{
    filter.Add(ViewQuizAttemptFields.QuizAttemptId == quizAttemptId);
}

var qf = new QueryFactory();
var q = qf.ViewQuizAttempt.Where(filter);
var results = new ViewQuizAttemptCollection();
results.GetMulti(q);
Frans Bouma | Lead developer LLBLGen Pro
matan86
User
Posts: 4
Joined: 13-Feb-2025
# Posted on: 14-Feb-2025 09:27:09   

Thank you, Otis, for your explanation. Yes, I was unfortunately stuck on my previous way of filtering on the view by mean of the lambda expression and, stubborn me, tried to pass the "filter" variable to the where.

Good to know that the way how I have implemented is the right one. Am I wrong in saying that the filtering documentation can be improved by adding also an example of how to consume the predicate just built?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 15-Feb-2025 07:25:43   

matan86 wrote:

Good to know that the way how I have implemented is the right one. Am I wrong in saying that the filtering documentation can be improved by adding also an example of how to consume the predicate just built?

You mean, how to use it with e.g. GetMulti?

Frans Bouma | Lead developer LLBLGen Pro
matan86
User
Posts: 4
Joined: 13-Feb-2025
# Posted on: 15-Feb-2025 11:59:03   

Otis wrote:

matan86 wrote:

Good to know that the way how I have implemented is the right one. Am I wrong in saying that the filtering documentation can be improved by adding also an example of how to consume the predicate just built?

You mean, how to use it with e.g. GetMulti?

Yes, exactly. How to build the predicate in the documentation is very clear and understandable, but I missed how to use it and that's why I opened a thread here. Perhaps it was me missing that explanation in the documentation...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 16-Feb-2025 07:31:17   
Frans Bouma | Lead developer LLBLGen Pro