Использование IEqualityComparer для поиска записей
Я использую следующий IEqualityComparer для удаления специальных символов из названия компании перед сравнением следующим образом:
public class CompanyNameIgnoringSpaces : IEqualityComparer<LeadGridViewModel>
{
public bool Equals(LeadGridViewModel x, LeadGridViewModel y)
{
var delimiters = new[] {' ', '-', '*', '&', '!'};
return delimiters.Aggregate(x.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, ''))
== delimiters.Aggregate(y.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, ''));
}
public int GetHashCode(LeadGridViewModel obj)
{
var delimiters = new[] {' ', '-', '*', '&', '!'};
return delimiters.Aggregate(obj.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, '')).GetHashCode();
}
}
Чтобы вызвать это при выполнении запроса, я использую следующее:
var results = result
.GroupBy(c => c, new CompanyNameIgnoringSpaces())
.Select(g => new LeadGridViewModel
{
LeadId = g.First().LeadId,
Qty = g.Count(),
CompanyName = g.Key.CompanyName,
}).OrderByDescending(x => x.Qty).ThenBy(x => x.CompanyName).ToList();
Как бы я использовал этот компаратор в запросе LINQ, чтобы найти все записи, соответствующие входной строке (название компании)?
Например:
public List<LeadGridViewModel> AllByName(string name, int company)
{
var result = (from t1 in db.Leads
where
t1.Company_ID == company && t1.Company_Name == name...
Поэтому вместо использования t1.Company_Name = = name, я хотел бы использовать use the equality comparer для этого, чтобы включить замена специального символа.
2 ответов:
Использование IEqualityComparer в запросе linqToDatabase: Если вы не можете инкапсулировать логику в форме, которую поставщик может перевести, то это должно быть сделано локально. Из маршрута, по которому вы идете с этой проблемой, я предполагаю, что поставщик не смог справиться с ней. Таким образом, мы можем сделать следующее на локальной стороне:
Втяните все это:
var results = result.ToArray() .GroupBy(c => c, new CompanyNameIgnoringSpaces()) .Select(g => new LeadGridViewModel { LeadId = g.First().LeadId, Qty = g.Count(), CompanyName = g.Key.CompanyName, }).OrderByDescending(x => x.Qty).ThenBy(x => x.CompanyName).ToList();ToLookup ()
var results = result .ToLookup(c => c, new CompanyNameIgnoringSpaces()) .Select(g => new LeadGridViewModel { LeadId = g.First().LeadId, Qty = g.Count(), CompanyName = g.Key.CompanyName, }).OrderByDescending(x => x.Qty).ThenBy(x => x.CompanyName).ToList();Поток результаты
var results = result.AsEnumerable() .GroupBy(c => c, new CompanyNameIgnoringSpaces()) .Select(g => new LeadGridViewModel { LeadId = g.First().LeadId, Qty = g.Count(), CompanyName = g.Key.CompanyName, }).OrderByDescending(x => x.Qty).ThenBy(x => x.CompanyName).ToList();Примечание: большинство вариантов sql имеют функцию replace, поэтому вы можете потенциально жестко закодировать replaces в выражение и, следовательно, сделать это на стороне сервера. Если вы хотите, чтобы он был многоразовым, вам нужно что-то вроде следующего:
private static Expression<Func<LeadGridViewModel,String>> leadGridTransform = (lead) => lead.CompanyName == null ? "", lead.CompanyName.Replace(' ','\0').Replace.... ;Которые затем можно будет использовать в запросных выражениях:
Здесь использовался тернарный оператор, поскольку он позволяет избежать дорогостоящих операций слияния на стороне сервера.var results = result.GroupBy(leadGridTransform)....Найти все записи для определенной строки: Здесь вы действительно хотите инвертировать сравнение и найти все строки, которые будут эквивалентны данной строке, а затем запросить название компании, содержащееся в них. Так что предположим, что БД.Leads-это таблица LeadGridViewModel, поэтому мы можем использовать компаратор
Неявная инверсия:
public List<LeadGridViewModel> AllByName(string name, int company) { var comparer = new CompanyNameIgnoringSpaces(); var group = db.Leads.Select(lead => new LeadGridViewModel { CompanyName = lead.CompanyName }) .AsEnumerable() .Where(lead => comparer.Equals(name, lead.CompanyName) .ToArray(); var result = db.Leads.Where(lead => lead.Company_ID == company) .Where(lead => group.Contains(lead.CompanyName))...Явная Инверсия:
private var delimiters = new[] {' ', '-', '*', '&', '!'}; public List<LeadGridViewModel> AllByName(string name, int company) { var atomicName = name.Trim().Split(delimiters); IEnumerable<String> permutations = atomicName.Aggregate( new String[] {""}, (accumulate,atom) => atom == "" ? accumulate.Join( delimiters,str => true,chr => true,(str,chr) => str + atom + chr.ToString()) : accumelate) .ToArray(); var result = db.Leads.Where(lead => lead.Company_ID == company) .Where(lead => permutations.Contains(lead.CompanyName))...Примечания: для инверсии сравнения оба эти метода имеют свои собственные ограничения. В первой реализации чем больше база данных, тем медленнее она строит доступную группировку. Для второй реализации чем больше разделителей имеет имя, тем больше времени потребуется для построения перестановок (экспоненциально). Если вы делаете жесткий код замены, то это может быть сделано на стороне сервера и, следовательно, избежать этих ограничений.
Код, используемый для вызова (и даже код, используемый внутри)
IEqualityComparison, не может быть переведен в SQL-запрос, поскольку код вIEqualityComparisonкомпилируется, а не строится с использованием объектовExpression.
Comments