grokky
grokky

Reputation: 9265

EF Core helper method for explicit loading references and collections

EF Core has support for explicit loading. The context has two overloads, one for references and one for collections.

Having two methods is not useful, and gets messy. I want a single method for accepting both as a params array.

So instead of this

await context.Entry(customer).Collection(e => e.Orders).LoadAsync();
await context.Entry(customer).Collection(e => e.Returns).LoadAsync();
await context.Entry(customer).Reference(e => e.Account).LoadAsync();

I want to do this:

await context.Entry(customer).Load(e=>e.Orders, e=>e.Returns, e=>e.Account);

I assume this is possible, because there is something similar with context.Include(...) which accepts both collections and references.

In my context class, I have this so far:

public async Task Load<TEntity>(TEntity entity, params Expression<Func<TEntity, object>>[] propertyExpressions)
  where TEntity : class
{

  foreach (var propertyExpression in propertyExpressions) {

    var isCollection = typeof(IEnumerable).GetTypeInfo()
                       .IsAssignableFrom(propertyExpression.Body.Type);

    if(isCollection)
    {
      await Entry(entity)
        .Collection(propertyExpression)     // problem is here !!!!!
        .LoadAsync();
    }
    else
    {
      await Entry(entity)
        .Reference(propertyExpression)
        .LoadAsync();
    }
  }
}

The problem line is shown above. The input is object but .Collection() expects IEnumerable<TProperty>.

How do I make this work?

Upvotes: 2

Views: 1253

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205589

Taking into account that both methods return NavigationEntry derived class, and both use Microsoft.EntityFrameworkCore.Internal.ExpressionExtensions.GetPropertyAccess method to get the PropertyInfo.Name from the passed lambda expression, you can use the same approach to retrieve the name and then use the Navigation method:

using Microsoft.EntityFrameworkCore.Internal;

public async Task Load<TEntity>(TEntity entity, params Expression<Func<TEntity, object>>[] propertyExpressions)
    where TEntity : class
{
    foreach (var propertyExpression in propertyExpressions)
    {
        var propertyName = propertyExpression.GetPropertyAccess().Name;
        await Entry(entity).Navigation(propertyName).LoadAsync();
    }
}

Upvotes: 5

Related Questions