Search code examples
c#linqdynamic-linq

Dynamic LINQ IQueryable (Generate Expression at runtime)


I have the following query

query.Join(
    relationEntity,
    entity => new { Prop1 = EF.Property<object>(entity, "Id"), Prop2 = Ef.Property...},
    relation => new { Prop1 = EF.Property<object>(relation, "EntityId"), Prop2 = EF.Property... },
    (Entity, Relation) => new { Entity, Relation })

I need to generate the keys at runtime. How can that be achieved? I already tried to build a Expression at runtime but it looks like the Join takes the recieved value literally so if I call a method there it gets translated to that method name instead of the result.

The method I'm testing with atm:

   private static object MyMethod(object entity, string name)
             => new { Id = EF.Property<object>(entity, name) };



   query.Join(
        relationEntity,
        entity => MyMethod(entity, "Id"),
        relation => MyMethod(relation, "EntityId"),
        (Entity, Relation) => new { Entity, Relation })

Solution

  • To Make your MyMethod an expression you have to approach it like this

    private static Expression<Func<T, object>> MyMethod<T>(string name) => 
             (T entity) => new { Id = EF.Property<object>(entity, name) };
    
    query.Join(
        relationEntity,
        MyMethod<entityType>("Id"),
        MyMethod<relationType>("EntityId"),
        (Entity, Relation) => new { Entity, Relation })
    

    The Method has to return an Expression, not any computed result.

    But as more complex your MyMethod will be, as less likely you will be able to convert it to SQL.

    This here is more about keeping your code shorter and more readable. There is nothing dynamic in there yet.

    Something like this is not a problem, since this selection is executed before SQL-Creation.

    private static Expression<Func<T, object>> MyMethod<T>(string name) 
    { 
        if (case 1)
             return (T entity) => new { Id = EF.Property<object>(entity, name) };
        if (case 2) 
             return (T entity) => new { Id = EF.Property<object>(entity, name), Id2 = ... something else }
    }