PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Thursday, November 3, 2022

[FIXED] How to write Repository method for .ThenInclude in EF Core 2

 November 03, 2022     .net-core, c#, entity-framework-core, lambda, repository-pattern     No comments   

Issue

I'm trying to write a repository method for Entity Framework Core 2.0 that can handle returning child collections of properties using .ThenInclude, but I'm having trouble with the second expression. Here is a working method for .Include, which will return child properties (you supply a list of lambdas) of your entity.

public T GetSingle(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties)
{
    IQueryable<T> query = _context.Set<T>();
    foreach (var includeProperty in includeProperties)
    {
        query = query.Include(includeProperty);
    } 

    return query.Where(predicate).FirstOrDefault();
}

Now here is my attempt at writing a method that will take a Tuple of two Expressions and feed those into a .Include(a => a.someChild).ThenInclude(b => b.aChildOfSomeChild) chain. This isn't a perfect solution because it only handles one child of a child, but it's a start.

public T GetSingle(Expression<Func<T, bool>> predicate, params Tuple<Expression<Func<T, object>>, Expression<Func<T, object>>>[] includeProperties)
{
    IQueryable<T> query = _context.Set<T>();
    foreach (var includeProperty in includeProperties)
    {
         query = query.Include(includeProperty.Item1).ThenInclude(includeProperty.Item2);              
    }

    return query.Where(predicate).FirstOrDefault();
}

Intellisense returns an error saying "The type cannot be inferred from the usage, try specifying the type explicitly". I have a feeling it's because the expression in Item2 needs to be classified as somehow related to Item1, because it needs to know about the child relationship it has.

Any ideas or better techniques for writing a method like this?


Solution

I found this repository method online and it does exactly what I wanted. Yared's answer was good, but not all the way there.

/// <summary>
/// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method default no-tracking query.
/// </summary>
/// <param name="selector">The selector for projection.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <param name="orderBy">A function to order elements.</param>
/// <param name="include">A function to include navigation properties</param>
/// <param name="disableTracking"><c>True</c> to disable changing tracking; otherwise, <c>false</c>. Default to <c>true</c>.</param>
/// <returns>An <see cref="IPagedList{TEntity}"/> that contains elements that satisfy the condition specified by <paramref name="predicate"/>.</returns>
/// <remarks>This method default no-tracking query.</remarks>
public TResult GetFirstOrDefault<TResult>(Expression<Func<TEntity, TResult>> selector,
                                          Expression<Func<TEntity, bool>> predicate = null,
                                          Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
                                          Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null,
                                          bool disableTracking = true)
{
    IQueryable<TEntity> query = _dbSet;
    if (disableTracking)
    {
        query = query.AsNoTracking();
    }

    if (include != null)
    {
        query = include(query);
    }

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

    if (orderBy != null)
    {
        return orderBy(query).Select(selector).FirstOrDefault();
    }
    else
    {
        return query.Select(selector).FirstOrDefault();
    }
}

Usage:

var affiliate = await affiliateRepository.GetFirstOrDefaultAsync(
    predicate: b => b.Id == id,
    include: source => source
        .Include(a => a.Branches)
        .ThenInclude(a => a.Emails)
        .Include(a => a.Branches)
        .ThenInclude(a => a.Phones));


Answered By - redwards510
Answer Checked By - Cary Denson (PHPFixing Admin)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing