C # Linq Удаляет символы из результатов для сравнения

#c# #sql-server #linq #predicate

#c# #sql-сервер #linq #предикат

Вопрос:

У меня есть запрос linq, который извлекает записи из базы данных SQL Server. Телефонные номера, например, хранятся в виде строк и могут содержать пробелы или символы, которые при поиске не найдены.

т. Е. я ищу номер телефона «0123456789», но в базе данных он хранится как «01234 567890» или «01234-567890» и т.д. В моем коде ниже вы можете видеть мои попытки удалить символы (правильно или неправильно!), Но я все еще не получаю никаких результатов, если не буду искать символы после пустого места «567890».

С помощью приведенного ниже кода:

«567890» возвращает правильные результаты

«01202 567890» не возвращает результатов

«01202567890» не возвращает результатов

     Expression<Func<Customer, bool>> SearchVals = ContainsInDescription("01234567890");

    var query = (from customer in data.Customers.Where(SearchVals)
                                 where customer.Deleted == false
                                 orderby customer.Name ascending
                                 select new
                                 {
                                     CustomerID = customer.CustomerID.ToString(),
                                     Name = customer.Name,
                                     Company = customer.Company,
                                     Home = customer.PhoneHome.Replace(" ", ""),
                                     Mobile = customer.PhoneMobile.Replace(" ", ""),
                                     Work = customer.PhoneWork.Replace(" ", ""),
                                     Email = customer.Email,
                                     Address1 = customer.Address.AddressLine1,
                                     Address2 = customer.Address.AddressLine2,
                                     City = customer.Address.City,
                                     County = customer.Address.County,
                                     Postcode = customer.Address.PostalCode,
                                     Country = customer.Address.Country
                                 }).Skip(totalToDisplay * page).Take(totalToDisplay);

public Expression<Func<Customer, bool>> ContainsInDescription(
                                                        params string[] keywords)
        {
            Expression<Func<Customer, bool>> predicate = PredicateBuilder.False<Customer>();
            foreach (string keyword in keywords)
            {
                string temp = keyword;

                //string predicate1 = PhoneHome.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim();
                string predicate2 = temp.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim();

                predicate = predicate.Or(p => p.Name.Contains(temp));
                predicate = predicate.Or(p => p.Company.Contains(temp));

                predicate = predicate.Or(p => p.PhoneHome.Contains(temp));
                predicate = predicate.Or(p => p.PhoneMobile.Contains(temp));
                predicate = predicate.Or(p => p.PhoneWork.Contains(temp));
                //predicate = predicate.Or(p => p.PhoneHome.ToString().Replace(" ", "").Replace("-", "").Contains(temp.ToString().Replace(" ", "").Replace("-", "")));
                //predicate = predicate.Or(p => p.PhoneMobile.ToString().Replace(" ", "").Replace("-", "").Contains(temp.ToString().Replace(" ", "").Replace("-", "")));
                //predicate = predicate.Or(p => p.PhoneWork.ToString().Replace(" ", "").Replace("-", "").Contains(temp.ToString().Replace(" ", "").Replace("-", "")));
                //predicate = predicate.Or(p => p.PhoneHome.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim() == temp.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim());
                //predicate = predicate.Or(p => p.PhoneMobile.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim() == temp.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim());
                //predicate = predicate.Or(p => p.PhoneWork.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim() == temp.ToString().Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "").Trim());

                predicate = predicate.Or(p => p.Email.Contains(temp));
                predicate = predicate.Or(p => p.Address.AddressLine1.Contains(temp));
                predicate = predicate.Or(p => p.Address.AddressLine2.Contains(temp));
                predicate = predicate.Or(p => p.Address.City.Contains(temp));
                predicate = predicate.Or(p => p.Address.County.Contains(temp));
                predicate = predicate.Or(p => p.Address.PostalCode.Contains(temp));
                predicate = predicate.Or(p => p.Address.Country.Contains(temp));
            }
            return predicate;
        }
  

Комментарии:

1. Вы чередуете только поисковый запрос, а не содержимое базы данных, поэтому сохраненное значение с пробелами или тире никогда не будет соответствовать.. Я думаю, вам следует добавить в свою таблицу вычисляемый индексированный столбец, содержащий удаленное значение, и использовать его в своем поиске. Любые другие попытки не будут разрешены.

Ответ №1:

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

 using System;
using System.Linq;
using System.Text;

public static void Main()
{
    Func<string, String> onlyNumbers = data 
      => data.Where(c => char.IsDigit(c))  // only keep digits
             .Aggregate(new StringBuilder(),(builder, c) => builder.Append(c))
             .ToString(); // gimme concatted string
    
    Console.WriteLine(onlyNumbers( "sadf(234)-23492sas" ));  // =>   "23423492"
}
  

используя вышеуказанный «очиститель», что-то вроде

 ...
Mobile = onlyNumbers(customer.PhoneMobile),
Home = onlyNumbers(customer.PhoneHome),
Mobile = onlyNumbers(customer.PhoneMobile),
Work = onlyNumbers(customer.PhoneWork),
...
  

и

 pred = pred.Or(p => p.Mobile.Contains(onlyNumbers(_some_input_)));
  

должно сработать.

Вместо char.IsDigit() вы могли бы определить свой собственный набор разрешенных символов (или также разрешить ‘ ‘), чтобы разрешить, например, международные номера предварительного набора, указанные как 41 1234 5678 90

Предостережение — это приведет к генерации цифр из любого текста и может привести к ложным срабатываниям:

 onlyNumbers("This 246 cars had 102 violations of rule 47.11 in the year 2012");
  

выдает строку "24610247112012" .