Как я могу воспроизвести "выберите некое целое число из foo, где некое такое целое число, как"% 50% "в Linq для сущностей? - PullRequest
0 голосов
/ 10 августа 2011

У меня есть приложение ASP.NET MVC, которое отображает данные в виде таблицы. Я хочу дать своим пользователям возможность поиска в таблице, поэтому я беру текстовую строку и передаю ее в свой служебный слой для построения запроса с использованием Linq to Entities.

Я хочу найти количество столбцов, используя строку. Некоторые из столбцов являются целыми числами (идентификаторы заказа), но пользователю нет дела до целых чисел и строк. Они хотят набрать «1200» и получить любой заказ с «1200» в номере заказа или «1200» в адресе.

Проблема в том, что я не могу найти способ построить запрос Linq-to-Entities, который приводит к SQL, который выглядит следующим образом:

select orderid, address from orders where orderid like '%1200%' or address like '%1200%'

Контекст базы данных:

    public DbSet<Person> Persons { get; set; }
    public DbSet<Worker> Workers { get; set; }
    public DbSet<WorkerSignin> WorkerSignins { get; set; }

Таблицы Persons и Workers находятся в соотношении от 1 до 0..1. Если рабочая запись существует, персональная запись также должна существовать. Они имеют один и тот же идентификатор. Рабочая запись не должна существовать, однако.

Таблицы Workers и WorkerSignins связаны, но не применяются из-за требований клиента. Работник имеет идентификационную карточку с номером штрих-кода (dwccardnum), но могут быть расхождения между выпущенными карточками и записями в БД, поэтому я записываю все отсканированные карточки в WorkerSignins, независимо от того, имеется ли соответствующая запись в таблице Workers.

Вот код, с которым я работаю:

            allWSI = signinRepo.GetAllQ()
                .Where(jj => jj.dateforsignin == date)
                .Select(a => a);

            if (!string.IsNullOrEmpty(search))
            {
                allWSI = allWSI
                    .Join(workerRepo.GetAllQ(), s => s.dwccardnum, w => w.dwccardnum, (s, w) => new { s, w })
                    .DefaultIfEmpty()
                    .Join(personRepo.GetAllQ(), oj => oj.w.ID, p => p.ID, (oj, p) => new { oj, p }).DefaultIfEmpty()
                    .DefaultIfEmpty()
                    .Where(jj => Convert.ToString(jj.oj.w.dwccardnum).Contains(search) ||
                                jj.p.firstname1.Contains(search) ||
                                jj.p.firstname2.Contains(search) ||
                                jj.p.lastname1.Contains(search) ||
                                jj.p.lastname2.Contains(search))
                    .Select(a => a.oj.s);
            }

Методы GetAllQ () возвращают объект IQueryable ().

Проблема в этой строке: .Where(jj => Convert.ToString(jj.oj.w.dwccardnum).Contains(search) ||

Я получаю эту ошибку: LINQ to Entities не распознает метод метода System.String ToString (Int32), и этот метод нельзя преобразовать в выражение хранилища. "

Если я возьму конверт и попробую это: .Where(jj => jj.oj.w.dwccardnum.Contains(search) ||

Я получаю эту ошибку: 'int' не содержит определения для 'Contains', а наилучшая перегрузка метода расширения 'System.Linq.ParallelEnumerable.Contains (System.Linq.ParallelQuery, TSource)' имеет несколько недопустимых аргументов

Так что вопрос ... Как мне создать предложение Where, чтобы сгенерировать похожее '% string%' и выполнить его для целочисленного столбца, используя Linq to Entities? (например, без использования LINQ to SQL)

Ответы [ 2 ]

2 голосов
/ 11 августа 2011

Один из вариантов - заменить ...

jj => Convert.ToString(jj.oj.w.dwccardnum).Contains(search)

... по:

jj => SqlFunctions.StringConvert((decimal)jj.oj.w.dwccardnum).Contains(search)

SqlFunctions - это статический класс в пространстве имен System.Data.Objects.SqlClient, и я считаю, что он работает только с SQL Server. Странное приведение к decimal необходимо, потому что StringConvert не имеет перегрузки для int, и без преобразования компилятор жалуется, что не может однозначно выбрать правильную перегрузку. (У него есть один для decimal? и один для double?.) Но я только что проверил, что приведенный выше код действительно работает (с SQL Server и предполагая, что dwccardnum равен int).

0 голосов
/ 10 августа 2011

Попробуйте это

            if (!string.IsNullOrEmpty(search))
            {
                int cardnum;
                bool searchIsInt = int.TryParse(search, out cardnum);

                allWSI = allWSI
                    .Join(workerRepo.GetAllQ(), s => s.dwccardnum, w => w.dwccardnum, (s, w) => new { s, w })
                    .DefaultIfEmpty()
                    .Join(personRepo.GetAllQ(), oj => oj.w.ID, p => p.ID, (oj, p) => new { oj, p }).DefaultIfEmpty()
                    .DefaultIfEmpty()
                    .Where(jj => (searchIsInt ? jj.oj.w.dwccardnum == cardnum : true) ||
                                jj.p.firstname1.Contains(search) ||
                                jj.p.firstname2.Contains(search) ||
                                jj.p.lastname1.Contains(search) ||
                                jj.p.lastname2.Contains(search))
                    .Select(a => a.oj.s);
            }

По сути, вы сначала проверяете, является ли поиск int, а затем используете его в своем linq, если он есть.

...