AGuyCalledGerald
AGuyCalledGerald

Reputation: 8150

Using reflection throws error in EF Core 3

We formerly used reflection to create linq queries, e.g. for the GetById method:

private IQueryable<T> GetQueryById(TKey id)
{
    var query = _dbset; //DbSet<T>

    var keyNames = _context.Model
            .FindRuntimeEntityType(typeof(T))
            .FindPrimaryKey()
            .Properties
            .Select(x => x.Name)
            .ToList();

    if (keyNames.Count() == 1)
    {
        query = query.Where(e => e.GetType().GetProperty(keyNames[0]).GetValue(e, null)
           .Equals(id)); //throws error
    }
        
    return query;
}

This does not seem to work any more in EF Core 3:

The LINQ expression 'DbSet .Where(c => c.GetType().GetProperty(__get_Item_0).GetValue( obj: c, index: null).Equals((object)__id_1))' could not be translated.

Is it possible to rewrite the query so that EF Core does not complain?

Upvotes: 1

Views: 666

Answers (1)

Svyatoslav Danyliv
Svyatoslav Danyliv

Reputation: 27406

You have to create predicate dynamically:

private IQueryable<T> GetQueryById(TKey id)
{
    IQueryable<T> query = _dbset; //DbSet<T>

    var keyNames = _context.Model
            .FindRuntimeEntityType(typeof(T))
            .FindPrimaryKey()
            .Properties
            .Select(x => x.Name)
            .ToList();

    if (keyNames.Count == 1)
    {
        var keyExpression = Expression.Constant(id);
        var entityParam   = Expression.Parameter(typeof(T), "e");
        var body          = Expression.Equal(Expression.PropertyOrField(entityParam, keyNames[0]), keyExpression);
        var predicate     = Expression.Lambda<Func<T, bool>>(body, entityParam);

        query = query.Where(predicate); 
    }
    else
      // better to throw exception
      throw new Exception($"Cannot find entity key.");
        
    return query;
}

Upvotes: 2

Related Questions