Метод для поиска по разным столбцам

126
07 апреля 2021, 17:10

У меня есть Form с ComboBox и TextBox. Первый содержит имена столбцов, второй содержит текст для поиска. В качестве источника ComboBox берет ListTypeSearch из элементов ItemSearch. В обработке нажатия кнопки Поиск вызывается метод Search().

Если дать имя столбца так, то ничего не найдется

EF.Functions.Like(item.Value, ...); // Value = "FullName"

Если указывать столбец из модели, поиск работает

EF.Functions.Like(w.FullName, ...); 

Можно ли в рамках одного метода Search() подменять столбец по которому должен идти поиск?

ListTypeSearch.Add(new ItemSearch { Value = "FullName", Display = "ФИО" });
ListTypeSearch.Add(new ItemSearch { Value = "PassportSeries", Display = "Серия" });
ListTypeSearch.Add(new ItemSearch { Value = "PassportNumber", Display = "Номер" });
public class ItemSearch
{
    public string Value { get; set; }
    public string Display { get; set; }
}
internal List<WorkerTableRow> Search(ItemSearch item, string text)
{
    try
    {
        Found = new List<WorkerTableRow>();
        using (ModelContext model = new ModelContext())
        {
            Found = (from w in model.Workers
                     where EF.Functions.Like(w.FullName, // этот код
                                             String.Format("%{0}%", text))
                     select new WorkerTableRow
                     {
                         ...
                     })
                     .ToList();
        }
    }
    catch (Exception ex) { ... }
    return Found;
}

Update

Сделал следующим образом. Это можно упростить? Может C# умеет сам возвращать свойства по имени.

where EF.Functions.Like(w.GetProperty(item.Value), 
                        String.Format("%{0}%", text))

public partial class Workers
{
    ...
    public string FullName { get; set; }
    public string PassportSeries { get; set; }
    public string PassportNumber { get; set; }
    public string GetProperty(string name)
    {
        switch (name)
        {
            case "FullName":
                return FullName;
            case "PassportSeries":
                return PassportSeries;
            case "PassportNumber":
                return PassportNumber;
            default:
                return string.Empty;
        }
    }
}
Answer 1

Я включил логирование запросов и посмотрел, что генерируется в том и другом случае.

Если использовать Like(w.FullName, ...), то получается следующий запрос:

Executed DbCommand (94ms) [Parameters=[@__Format_1='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']
SELECT [w].[WorkerId], [w].[FullName], [w].[PassportNumber], [w].[PassportSeries]
FROM [Workers] AS [w]
WHERE [w].[FullName] LIKE @__Format_1

Видно, что в WHERE используется LIKE и передаётся параметр.

Если использовать Like(w.GetProperty(item.Value), ...), то получается следующее:

The LINQ expression 'where __Functions_0.Like([w].GetProperty(__item_1), __Format_2)' could not be translated and will be evaluated locally.

Executed DbCommand (47ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [w].[WorkerId], [w].[FullName], [w].[PassportNumber], [w].[PassportSeries]
FROM [Workers] AS [w]

Во-первых, выдаётся предупреждение, что метод GetProperty не может быть транслирован в sql и будет выполнен локально.

Во-вторых, в самом запросе отсутствует WHERE и нет параметров.

Вообще, EF Core известен тем, что по умолчанию выполняет на клиенте те действия, которые не может транслировать в sql на сервере. Это может приводить к вытягиванию большого объёма данных и снижения производительности.

Breaking changes included in EF Core 3.0 - в этой статье написано, что в EF Core 3 поведение изменится и станет таким же, как в обычном EF: если запрос не может быть транслирован в действия на сервере, то будет выброшено исключение. А если кому-то всё же нужно продолжить выполнение linq-запроса локально, всегда можно вызвать AsEnumerable().

Решение:

List<WorkerTableRow> Search(ItemSearch item, string text)
{
    string pattern = string.Format("%{0}%", text);
    using (var model = new ModelContext())
    {
        IQueryable<Worker> query = model.Workers;
        if (item.Value == "FullName")
            query = query.Where(w => EF.Functions.Like(w.FullName, pattern));
        if (item.Value == "PassportSeries")
            query = query.Where(w => EF.Functions.Like(w.PassportSeries, pattern));
        if (item.Value == "PassportNumber")
            query = query.Where(w => EF.Functions.Like(w.PassportNumber, pattern));
        return query.Select(w => new WorkerTableRow { ... }).ToList();
    }
}
READ ALSO
Где метод Table&lt;T&gt; Update?

Где метод Table<T> Update?

Использую дженерик репозиторий в проекте и и не могу понять как реализовать редактирование модели? Использую adonet и нигде не могу найти информацию...

118
c# try catch Вложенные

c# try catch Вложенные

Как происходит обработка блока finally, если идет конструкция

133
Как выполнить асинхронную операцию с возвращаемым результатом фоном (то есть проигнорировав результат) в C#

Как выполнить асинхронную операцию с возвращаемым результатом фоном (то есть проигнорировав результат) в C#

У меня есть асинхронная функция, она возвращает результатИногда он мне нужен, иногда нет

95
Не удается верно указать индексы дублирующихся символов в строке

Не удается верно указать индексы дублирующихся символов в строке

Необходимо вывести индексы начала и конца последовательности дублирующихся гласных символов

85