Повторное использование функции для определенного свойства в любом выражении LINQ to SQL

У меня есть следующий код:

var dbContacts = dbContacts.Where(k => k.Name != null && k.Name.ToLower().IndexOf(model.name.ToLower()) > -1);

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

var dbContacts = dbContacts.Where(k => contains(k.Name,model.name));

// or

var dbContacts = dbContacts.Where(k => k.Name.ContainsIgnoreCase(model.name));

Я проверил эту тему, все ответы используют Expression, где он повторно использует все выражение вместо конкретной функции в этом выражении для определенного свойства.

Однако то, что я пробовал до сих пор (и получить выражение LINQ, не удалось перевести):

// defining a delegate Func

Func<string, string, bool> contains = (string str, string value) =>
{
   return str != null && str.ToLower().IndexOf(value.ToLower()) > -1;
};

// using an extension
public static bool ContainsIgnoreCase(this string str, string value)
{
    return str.IndexOf(value, StringComparison.OrdinalIgnoreCase) > -1;
}

Я хотел бы повторно использовать эту функцию для определенного свойства в любом выражении LINQ to SQL.

Любые идеи?


person Ali Kleit    schedule 26.04.2020    source источник
comment
Во-первых, вам не нужна проверка на null, потому что инструкция транслируется в SQL. Второй предикат игнорирует ненулевые строки в SQL. Во-вторых, вам, вероятно, не нужны вызовы ToLower (которые убивают производительность), потому что используется сопоставление базы данных, которое в большинстве случаев нечувствительно к регистру. Остается короткий предикат, обобщение которого, возможно, не стоит усилий. Если вы все еще хотите этого, в сети есть много примеров, как это сделать.   -  person Gert Arnold    schedule 27.04.2020
comment
Замените Func<T, bool> на Expression<Func<T,bool>>.   -  person Jeremy Lakeman    schedule 27.04.2020
comment
@JeremyLakeman Я процитировал, что в моем вопросе использование Expression будет означать повторное использование всего выражения вместо конкретной функции в этом выражении для определенного свойства.   -  person Ali Kleit    schedule 27.04.2020
comment
EF Core может переводить только выражения или вызовы известных функций. Он ничего не может сделать с Func<T,bool>, которого не распознает. Ваша contains лямбда не может быть преобразована в sql.   -  person Jeremy Lakeman    schedule 27.04.2020
comment
Я хотел сказать, что второй предикат игнорирует нулевые строки в SQL.   -  person Gert Arnold    schedule 27.04.2020
comment
@GertArnold понял тебя. Тем не менее, это пример длинной строки кода... для изложения моей точки зрения. так что эта функция должна повторяться в нескольких условиях. и кажется неправильным писать код несколько раз.   -  person Ali Kleit    schedule 27.04.2020


Ответы (1)


Насколько я понял, вы пытаетесь создать функцию делегата, которая будет использоваться в качестве фильтра в запросах Linq. поэтому в конце вам нужно использовать делегата Func<string, string, bool>, который вы создали следующим образом:

var dbContacts = dbContacts.Where(k => contains(k.Name,model.name));

это не сработает, потому что Where принимает Func<T, bool>, поэтому вам нужно сделать что-то вроде этого:

Func<EntityModelClass, bool> contains = (EntityModelClass entity) =>
{
    return entity.Name != null && entity.Name.ToLower().IndexOf(entity.Model.ToLower()) > -1;
};

где EntityModelClass — объект dbContacts.

то вы можете сделать это:

var dbContacts = dbContacts.Where(contains);

Однако ваша функция может быть лучше, если вы сделаете это:

!string.IsNullOrEmpty(k.Name) && k.Name.IndexOf(model.name, StringComparison.InvariantCultureIgnoreCase) > -1

ОБНОВЛЕНИЕ:

Из того, что я понял из ваших комментариев, вы, вероятно, ищете решение для отражения, в котором вы просто передаете имя свойства и модель.

вот пример:

public static class LinqExtension
{
    public static IEnumerable<T> WhereContains<T>(this IEnumerable<T> source, string propertyName, string model)
    {
        if(string.IsNullOrEmpty(propertyName)) { throw new ArgumentNullException(nameof(propertyName)); }

        if (string.IsNullOrEmpty(model)) { throw new ArgumentNullException(nameof(model)); }

        foreach (var item in source)
        {
            var property = item.GetType().GetProperty(propertyName);

            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }

            var value = property.GetValue(item, null)?.ToString();

            if (!string.IsNullOrEmpty(value) || value.IndexOf(model, StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                yield return item;
            }
        }
    }
}

тогда ваше использование будет таким:

var contacts = dbContacts.WhereContains("Name", model.name);

Надеюсь, это то, что вы ищете.

person iSR5    schedule 26.04.2020
comment
Это оставит меня, чтобы определить класс сущности, который является моей проблемой в начале. - person Ali Kleit; 27.04.2020
comment
основная проблема заключается в повторном использовании функции для определенного свойства вместо повторного использования всего выражения для статического объекта. - person Ali Kleit; 27.04.2020
comment
@AliKleit, значит, у вас есть несколько объектов с одинаковым свойством Name? который вы хотите автоматизировать, чтобы вы могли передать ему только model.name? это правильно ? - person iSR5; 27.04.2020
comment
На самом деле нет, скажем, для любой сущности со строковым типом данных. поэтому его можно повторно использовать для этого типа данных... - person Ali Kleit; 27.04.2020