As an expression of merging in a Select method with Linq

I am trying to do a generic for Selectors components. It should provide the result of the default template, which is based on the type that we created under the name SelectorViewModel, which has Id, a Descriptionand a Code. Today we have a method that does this using the following query:

var result = Queryable.Where(x => .... )
                      .OrderBy(x => ... )
                      .Select(x => SelectorViewModel(x.Id, 
                                                     x.Name, 
                                                     x.Code))
                      .ToList();

It works great, but we will have many such methods. The question is how to make the fields defined in the method Selectavailable to the parameter SelectorViewModel? For sample:

public IEnumerable<SelectorViewModel> Selector<T>(.. idExpression, .. descriptionExpression, .. codeExpression)
{
    var result = session.Query<T>
                        .Where(x => .... )
                        .OrderBy(x => ... )
                        .Select(x => SelectorViewModel(idExpression,  // id
                                                       descriptionExpression, // description
                                                       codeExpression /*code*/))
                        .ToList();

   return result;
}

I would like to have something like this when using this method:

var result = repository.Selector(x => x.Id, x => x.Name, x => x.Code);

And add these arguments to the expression in the method Select. Is it possible?

Thank.

+4
2

- :

public IEnumerable<SelectorViewModel> Selector<T>(
        Func<T, int> idExpression, 
        Func<T, string> descriptionExpression,
        Func<T, string> codeExpression)
    {
        var result = session.Query<T>
                 .Where(x => .... )
                 .OrderBy(x => ... )
                 .Select(x => new SelectorViewModel(idExpression(x), descriptionExpression(x), codeExpression(x)))
                 .ToList();

        return result;
    }

"Factory method", factory, T SelectorViewModel (- ):

public class SelectorViewModel
{
    public static SelectorViewModel GetSelectorViewModel<T>(T input)
    {
        //create SelectorViewModel how do you prefer
        return new SelectorViewModel(input.Id, input.Description, input.Code);
    }

    public SelectorViewModel(int id, string description, int code)
    {
        // TODO
    }
}

public IEnumerable<SelectorViewModel> Selector<T>(Func<T, SelectorViewModel> factoryMethod)
{
     var result = session.Query<T>
                 .Where(x => .... )
                 .OrderBy(x => ... )
                 .Select(x => factoryMethod(x))
                 .ToList();
     return result;
}

, () , , , :

x => x.property > 2 ? x.name.ToString() : (x.property < 0 ? x.description : x.description + "a")

,

  • /
  • ()

[ps: , , OOP (https://en.wikipedia.org/wiki/Factory_method_pattern)]

+4

, (EF NHibernate), , , ExpressionVisitor:

public static class QueryableExtensions
{
    public static IQueryable<SelectorViewModel> ToSelectorViewModel<T>(
        this IQueryable<T> source, 
        Expression<Func<T, long>> idSelector,
        Expression<Func<T, string>> descriptionSelector,
        Expression<Func<T, string>> codeSelector
    )
    {
        Expression<Func<long, string, string, SelectorViewModel>> prototype =
            (id, description, code) => new SelectorViewModel { Id = id, Description = description, Code = code };
        var parameter = Expression.Parameter(typeof(T), "e");
        var body = prototype.Body
            .ReplaceParameter(prototype.Parameters[0], idSelector.Body.ReplaceParameter(idSelector.Parameters[0], parameter))
            .ReplaceParameter(prototype.Parameters[1], descriptionSelector.Body.ReplaceParameter(descriptionSelector.Parameters[0], parameter))
            .ReplaceParameter(prototype.Parameters[2], codeSelector.Body.ReplaceParameter(codeSelector.Parameters[0], parameter));
        var selector = Expression.Lambda<Func<T, SelectorViewModel>>(body, parameter);
        return source.Select(selector);
    }
}

:

public static partial class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }

    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}

, , idSelector, descriptionSelector codeSelector, , :

var result = Queryable.Where(x => .... )
                      .OrderBy(x => ... )
                      .ToSelectorViewModel(idSelector, descriptionSelector, codeSelector) 
                      .ToList();
+3

Source: https://habr.com/ru/post/1665784/


All Articles