#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"
.