gmesorio
gmesorio

Reputation: 453

Entity Framework Generic repository including properties through parameter

I have an implementation of a Generic Repository in Entity Framework which I am trying to improve to use the .Include(..) function provided by EF instead of including the navigation properties by string, in order to be able to safely rename properties.

Below is my current code:

public IQueryable<T> GetAll(
        Expression<Func<T, bool>> filter = null,
        Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<T> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query);
        }
        else
        {
            return query;
        }
    }

I currently use this in the following way:

repository.GetAll(
    u => u.Name = "John",
    u => u.OrderBy(x => x.Name),
    "Address.State",
);

My question is: how can I change the method in order to be able to call it in the following way (or similar):

repository.GetAll(
    u => u.Name = "John",
    u => u.OrderBy(x => x.Name),
    u => u.Include(x => x.Address).ThenInclude(x => x.State),
);

Upvotes: 4

Views: 6700

Answers (3)

Reza Aghaei
Reza Aghaei

Reputation: 125197

I suggest you to keep two methods, one accepting string params and one expression params. Some of the clients of your repository can work better with the string signature and some of them can work better with expression signature which brings IntelliSense for them.

public IQueryable<T> GetAll(params string[] including)
{
    var query = dbSet.AsQueryable();
    if (including != null)
        including.ToList().ForEach(include =>
        {
            if (!string.IsNullOrEmpty(include))
                query = query.Include(include);
        });
    return query;
}

public IQueryable<T> GetAll(params Expression<Func<T, object>>[] including)
{
    var query = dbSet.AsQueryable();
    if (including != null)
        including.ToList().ForEach(include =>
        {
            if (include != null)
                query = query.Include(include);
        });
    return query;
}

Make sure you have added using System.Data.Entity;.

You can implement the logic for filter and sort the same way. For the string params signature for filter and sort, you can use System.Linq.Dynamic package.

Example:

var result1 = schoolRepository.GetAll("Students", "Teachers");
var result2 = schoolRepository.GetAll(x=>x.Students, x=>x.Teachers);

Upvotes: 9

NaDeR Star
NaDeR Star

Reputation: 655

protected internal IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includeProperties)
{
    var query = RetrieveQuery();

    if (predicate != null)
    {
        query = query.Where(predicate).AsQueryable();
    }

    if (includeProperties != null)
    {
        query = _queryableUnitOfWork.ApplyIncludesOnQuery(query, includeProperties);
    }

    return (query);
}

And this method called there

public IQueryable<TEntity> ApplyIncludesOnQuery<TEntity>(IQueryable<TEntity> query, params Expression<Func<TEntity, object>>[] includeProperties) where TEntity : class, IEntity
{
    // Return Applied Includes query
    return (includeProperties.Aggregate(query, (current, include) => current.Include(include)));
}

Filter Method Call

 public IEnumerable<ShowStockProductDto> GetActiveShowStockProductListByProduct(int productId)
            {
                var foundedPStockroducts = Filter(
                    ent => ent.ProductId == productId && ent.IsActive,
                    ent => ent.StockProductPrices,
                    ent => ent.StockProductDepots,
                    ent => ent.StockProductSpecificationValues,
                    ent => ent.StockProductSpecificationValues.Select(spsv => spsv.SpecificationValue)
                    );

                // Map foundedPStockroducts to showStockProductList
                var showStockProductList = TypeAdapterFactory.Adapter.Adapt<IEnumerable<ShowStockProductDto>>(foundedPStockroducts).ToList();

                return (showStockProductList);
            }

Upvotes: 3

valerysntx
valerysntx

Reputation: 526

You can use the params Expression<Func<T, object>>[] includeProperties instead of string parameter

public IQueryable<T> GetAll(
    Expression<Func<T, bool>> filter = null,
    Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
    params Expression<Func<T, object>>[] includeProperties)
{
    IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties)
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query);
        }
        else
        {
            return query;
        }
}

Upvotes: 2

Related Questions