Использование «Match» в выражении Linq - PullRequest
5 голосов
/ 16 августа 2010

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

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

base {System.SystemException} = {"LINQ to Entities does not recognize the method 'System.Text.RegularExpressions.MatchCollection Matches(System.String)' method, and this method cannot be translated into a store expression."}”

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

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();
}

Ответы [ 4 ]

16 голосов
/ 16 августа 2010

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

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

РЕДАКТИРОВАТЬ: Если вам на самом деле нужна гибкость регулярного выражения, вам, вероятно, следует сначала получить идентификаторы устройства (и только идентификаторы устройства) обратно к клиенту, а затем выполнить регулярное выражение для них, и, наконец, получить остальные данные, соответствующие этим запросам:

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();
4 голосов
/ 16 августа 2010

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

Как указано в комментарии Пола Руэйна, StartsWith будет работать.Это может быть переведено LinqToEntities в WHERE DeviceId LIKE 'DEVICE%'.

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

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

Это приведет к следующему: WHERE DeviceId LIKE '%DEVICE%'.

1 голос
/ 16 августа 2010

Помните, что при использовании 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.

0 голосов
/ 16 августа 2010

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

    filterText = @"DEVICE.";


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

                          select d;
            return devices.ToList();
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...