каждое свойство объекта Parameter, отличное от NULL, добавляемое в предикат выражения как условие - PullRequest
6 голосов
/ 10 марта 2020

Я ищу способ динамического построения выражения на основе параметров метода.

Это фрагмент кода из моего метода обслуживания, в котором я хотел бы построить выражение предиката.

    public async Task<Account> GetCustomerAccountsAsync(Parameters params)
    {
        var items = await _unitOfWork.Accounts.GetWhereAsync(a => a.CustomerId == params.CustomerId && ... );
        ...
    }

GetWhereAsyn c - это метод из репозитория generi c, который выглядит следующим образом:

    public async Task<IEnumerable<TEntity>> GetWhereAsync(Expression<Func<TEntity, bool>> predicate)
    {
        return await Context.Set<TEntity>().Where(predicate).ToListAsync();
    }

И Параметры класс:

    public class Parameters
    {
        public string CustomerId { get; set; }
        public string AccountId { get; set; }
        public string ProductId { get; set; }
        public string CurrencyId { get; set; }
    }

Я хотел бы реализовать следующее: каждый параметр свойство объекта, которое не является нулевым , добавляется в предикат выражения в качестве условия.

Например, если CustomerId и AccountId имеют некоторые значения, я хотел бы динамически создать выражение предиката, которое будет иметь функциональность, аналогичную следующему предикату:

    var items = await _unitOfWork.Accounts.GetWhereAsync(a => a.CustomerId == params.CustomerId && a.AccountId == params.AccountId);

Ценю любую помощь.

Ответы [ 2 ]

5 голосов
/ 10 марта 2020

Вам не нужно использовать выражения для динамического построения чего-либо здесь. Вы можете сделать что-то вроде этого:

_unitOfWork.Accounts.Where(a =>
    (params.CustomerId == null || a.CustomerId == params.CustomerId) &&
    (params.AccountId == null || a.AccountId == params.AccountId) &&
    (params.ProductId == null || a.ProductId == params.ProductId) &&
    (params.CurrencyId == null || a.CurrencyId == params.CurrencyId)
);

Вот как я делал запросы раньше для формы поиска с несколькими необязательными параметрами поиска.

4 голосов
/ 10 марта 2020

В настоящее время я много работаю с выражениями, поэтому думаю, что смогу вам помочь.

Я только что создал собственный код для вас.

Код подтверждает, что вы добавляете свойства в свой отфильтрованный класс (Account) без необходимости изменения кода построения фильтра.

Код фильтрует строку Properties и использует ее для создания предиката.

public Func<Account, bool> GetPredicate(Parameters parameters)
{
    var stringProperties = typeof(Parameters)
    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
    .Where(x => x.PropertyType == typeof(string));

    var parameterExpression = Expression.Parameter(typeof(Account));

    var notNullPropertyNameToValue = new Dictionary<string, string>();

    BinaryExpression conditionExpression = null;

    foreach (var stringProperty in stringProperties)
    {
        var propertyValue = (string)stringProperty.GetValue(parameters);
        if (propertyValue != null)
        {
            var propertyAccessExpression = Expression.PropertyOrField(parameterExpression, stringProperty.Name);
            var propertyValueExpression = Expression.Constant(propertyValue, typeof(string));
            var propertyTestExpression = Expression.Equal(propertyAccessExpression, propertyValueExpression);

            if (conditionExpression == null)
            {
                conditionExpression = propertyTestExpression;
            }
            else
            {
                conditionExpression = Expression.And(conditionExpression, propertyTestExpression);
            }
        }
    }

    //Just return a function that includes all members if no parameter is defined.
    if (conditionExpression == null)
    {
        return (x) => true;
    }

    var lambdaExpression = Expression.Lambda<Func<Account, bool>>(conditionExpression, parameterExpression);
    return lambdaExpression.Compile();
}

Возвращает типизированный предикат, который вы можете используйте, например, в Linq.

См. этот пример:

void Main()
{
    var customers = new List<Account>()
    {
        new Account()
        {
            CustomerId = "1",
        },
        new Account()
        {
            CustomerId = "2",
        }
    };
    var predicate = GetPredicate(new Parameters() { CustomerId = "1" });

    customers.Where(predicate);
}

Если вам нужна помощь, не стесняйтесь спрашивать!

...