0

I am attempting to build a lambda from data.

The module entity has an AlgNo property of type string. I am trying to get a simple sample code to run before attempting the more advanced case.

Consider two entities "Composition" and "Module". Composition has multiple modules. When I retrieve compositions from the database, I want to only load the moduletypes that are relevant for the use case. Loading all modules for every composition would take a lot of memory. Eg. If composition if of type "A", I want to load modules with AlgNo equaling "25","51" or "53". So the hard coded case would be.

EF_Repo.Compositions.Where( <some clause)
    .Include ( comp => comp.Modules.Where( m=> (m.Composition == "A" && new[]{"25","51", "53"}.Contains(m.AlgNo))) 
        || ((m.Composition == "B" && new[] {"15","21"}.Contains(m.AlgNo)))));

This generates the proper SQL to filter server side. However, The exact modules for each composition type are represented in the domain model, so I hope to generate the predicate from code.

(Please ignore that "AlgNo" is a string type.)

In order to get there, I want to start with the simple case of creating a Expression<Func<Module,bool>>. I do this by running the two variations side by side in LINQPad and instecting the resulting Expression tree. However, I am getting an error message. "InvalidOperationException: The LINQ expression 'm' could not be translated."

void Main()
{
    Modules.Where(CreateLambda()).Take (100).Dump();
    //Modules.Where(m=>m.AlgNo=="48").Take (100).Dump();
}

Expression<Func<LINQPad.User.Module,bool>> CreateLambda()
{
    var modpar = Expression.Parameter(typeof(LINQPad.User.Module),"m");
    var algnoProp = typeof(LINQPad.User.Module).GetProperty(nameof(LINQPad.User.Module.AlgNo));
    var algnoaccessor = Expression.Property(modpar,algnoProp);
    var ma = Expression.MakeMemberAccess(modpar,algnoProp);
    
    var no48 = Expression.Constant("48");
    var equality = Expression.Equal(no48,ma);
    
    var lambda = Expression.Lambda<Func<LINQPad.User.Module,bool>>(equality,false,Expression.Parameter(typeof(LINQPad.User.Module),"m"));
    
    return lambda;
}

I an struggling on how to use the various factory methods found at "Expression." to generate the structure that the compiler generates autaomatically when passing in the labmda expression.

5
  • 1
    Expression.Lambda expects body (which in your case is the equality variable) and parameters (which in your case is single modpar variable), so the call should be Expression.Lambda<Func<LINQPad.User.Module,bool>>(equality, modpar) Commented May 6, 2024 at 12:24
  • I have answered the similar your question. Have you learned anything? Use ReadableExpressions for visualisation what you have built. Commented May 6, 2024 at 12:39
  • @SvyatoslavDanyliv Yes, indeed. I confirmed that the SQL generated comes out as desired. Adding to it, it seems that teh AsSplitQuery() option is the most scalable option. But I will re run the bench marking when I generate the Expression from code. Commented May 6, 2024 at 13:05
  • @IvanStoev That makes sense. I didn't even look there since the error message at didn't point me in that direction. I tested it and it works. Commented May 6, 2024 at 13:07
  • What is wrong with my extension? It is easy to extend it to accept any type for values. Commented May 6, 2024 at 13:33

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.