Home > Software engineering >  .Net Web API - Manager interaction with repository Find(Expression<Func<TEntity, bool>>
.Net Web API - Manager interaction with repository Find(Expression<Func<TEntity, bool>>

Time:06-09

I have issue with implementation Get method into my manager class. How do i need to filter and where i need to write filter method.

In short - i have data class Gym, repository class and method Find in it. I wrote methods in data classes - IsAppreciateToRequest(RequestName) to do smth like this in manager class

public IEnumerable<GymDto> GetGyms(GetGymRequest request)
{
    return _gymRepository
           .Find(gym => gym.IsAppreciateToRequest(request))
           .AsEnumerable()
           .Select(GymDto.FromEntityToDto);
}

I think this is shitcode, but also idk how to get rid of this and how to write it proper way(before this i had Get method like 30-50 lines longer in every manager class)

IsAppreciateToRequest method:

 public bool IsAppreciateToRequest(GetGymRequest other)
        {
            return (string.IsNullOrEmpty(other.Name) || Name == other.Name)
                   &&  (string.IsNullOrEmpty(other.Location) || Location == other.Location) 
                   && (other.SectionRequest == null || Sections.All(section => section.IsAppreciateToRequest(other.SectionRequest)));
        }

CodePudding user response:

You can use LINQKit for injecting Expression Tree into filters. It is needed to configure DbContextOptions:

builder
    .UseSqlServer(connectionString) // or any other provider
    .WithExpressionExpanding();     // enabling LINQKit extension

Your classes should be extended with static function which returns Expression<Func<>> and current methods should have ExpandableAttribute

For example:

public class Gym
{
    [Expandable(nameof(IsAppreciateToRequestImpl)]
    public bool IsAppreciateToRequest(GetGymRequest other)
    {
        return (string.IsNullOrEmpty(other.Name) || Name == other.Name)
                && (string.IsNullOrEmpty(other.Location) || Location == other.Location) 
                && (other.SectionRequest == null || Sections.All(section => section.IsAppreciateToRequest(other.SectionRequest)));
    }

    private static Expression<Func<Gym, GetGymRequest, bool>> IsAppreciateToRequestImpl()
    {
        // firs parameter is current object
        return (gym, other) => (string.IsNullOrEmpty(other.Name) || gym.Name == other.Name)
                && (string.IsNullOrEmpty(other.Location) || gym.Location == other.Location) 
                && (other.SectionRequest == null || gym.Sections.All(section => section.IsAppreciateToRequest(other.SectionRequest)));
    }
}

// the same technique as in Gym class
public class Section
{
    [Expandable(nameof(IsAppreciateToRequestImpl)]
    public bool IsAppreciateToRequest(GetSectionRequest other)
    {
        return // unknown;
    }

    private static Expression<Func<Section, GetSectionRequest, bool>> IsAppreciateToRequestImpl()
    {
        // firs parameter is current object
        return (section, other) => // unknown;
    }
}

Then LINQKit will expand expressions returned by your static methods and will inject conditions into predicate.

The same approach can be used for projecting entity to DTO. Similar my answer here, which also shows known alternatives for LINQKit.

  • Related