Использование «Match» в операторе Linq

У меня есть таблица с двумя записями (их будет много во время выполнения). deviceId записей: «DEVICE1» и «DEVICE2». Я хочу использовать регулярное выражение для извлечения записей.

Приведенный ниже код компилируется, но не возвращает результат. При наведении курсора на оператор «devices.ToList ()» я получаю следующую ошибку:

base {System.SystemException} = {"LINQ to Entities не распознает метод 'System.Text.RegularExpressions.MatchCollection Matches (System.String) ', и этот метод нельзя преобразовать в выражение хранилища. " } »

Может кто-нибудь показать мне, как я могу изменить свой запрос, чтобы он возвращал записи, основанные на выражении?

filterText = @"DEVICE.";
Regex searchTerm = new Regex(filterText);

using (var ctx = new MyEntities())
{
 var devices = from d in ctx.Devices
                let matches = searchTerm.Matches(d.DeviceId)
                where matches.Count > 0
                select ((Device)d);
return devices.ToList();
}
7
задан thecoshman 18 May 2018 в 11:46
поделиться

4 ответа

Я не верю, что вы можете использовать регулярные выражения с LINQ to Entities. Однако похоже, что вы просто пытаетесь найти устройства, которые начинаются с «DEVICE», поэтому запрос будет следующим:

return ctx.Devices.Where(d => d.DeviceId.StartsWith("DEVICE"))
                  .ToList();

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

Regex regex = new Regex(...);

var deviceIds = ctx.Devices.Select(d => DeviceId).AsEnumerable();

var matchingIds = deviceIds.Where(id => regex.IsMatch(id))
                           .ToList();

var devices = ctx.Devices.Where(d => matchingIds.Contains(d.DeviceId));

Предполагается, что это действительно будет дорого стоить получить все данные для всех устройств для начала. Если это не так уж плохо, это был бы более простой вариант. Чтобы принудительно выполнять обработку в процессе, используйте AsEnumerable () :

var devices = ctx.Devices.AsEnumerable()
                         .Where(d => regex.IsMatch(d.DeviceId))
                         .ToList();
17
ответ дан 6 December 2019 в 08:13
поделиться

Помните, что при использовании Entity Framework или Linq to Sql ваш запрос в конечном итоге переводится в SQL. SQL не понимает ваш объект регулярного выражения и не может использовать его совпадения на стороне сервера. Чтобы легко использовать свой RegEx, вы можете вместо этого сначала получить все устройства с сервера, а затем использовать существующую логику. например

using (var ctx = new MyEntities()) 
{ 
    var devices = from Device d in ctx.Devices select d;

    // Retrieve all the devices:
    devices = devices.ToList();

    devices = from d in devices
                  let matches = searchTerm.Matches(d.DeviceId) 
                  where matches.Count > 0 
                  select ((Device)d); 

    return devices.ToList(); 
}

Это действительно связано с затратами на извлечение большего количества данных, чем вам нужно, возможно, намного больше. Для сложной логики вы можете рассмотреть хранимую процедуру, которая потенциально может использовать тот же RegEx через функции CLR.

1
ответ дан 6 December 2019 в 08:13
поделиться

LinqToEntities не поддерживает передачу Regex'ов в базу данных. Просто сделайте Contains (который преобразуется в sql... where DeviceId Like '%DEVICE%').

    filterText = @"DEVICE.";


    using (var ctx = new MyEntities())
    {
            var devices = from d in ctx.Devices
                          d.DeviceId.Contains(filterText)

                          select d;
            return devices.ToList();
        }
0
ответ дан 6 December 2019 в 08:13
поделиться

Вы всегда должны помнить, что ваши запросы LinqToEntities должны быть преобразованы в запросы SQL. Поскольку SQL Server не поддерживает регулярные выражения, это не может работать.

Как указано в комментарии Пола Руана, StartsWith будет работать. LinqToEntities может перевести это в , ГДЕ DeviceId LIKE 'DEVICE%' .

Если StartsWith недостаточно, потому что вам может понадобиться искать строки в середине столбцов базы данных, Contains также будет работать:

var devices = from d in ctx.Devices
              where d.DeviceId.Contains("DEVICE")
              select d;

Это приведет к следующему : ГДЕ DeviceId КАК "% DEVICE%" .

4
ответ дан 6 December 2019 в 08:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: