我正在使用以下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, '\0'))
== delimiters.Aggregate(y.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, '\0'));
}
public int GetHashCode(LeadGridViewModel obj)
{
var delimiters = new[] {' ', '-', '*', '&', '!'};
return delimiters.Aggregate(obj.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, '\0')).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,而是使用相等比较器来包含特殊字符替换。
答案 0 :(得分:1)
你做不到。用于调用(甚至是{内部使用的代码)IEqualityComparison
的代码不能转换为SQL查询,因为IEqualityComparison
中的代码是编译的,而不是使用Expression
个对象构建的。
答案 1 :(得分:1)
在linqToDatabase查询中使用IEqualityComparer: 除非您能够以提供者可以翻译的形式封装逻辑,否则必须在本地完成。从您使用此问题的路线我认为提供商无法处理它。所以我们可以在本地做以下事情:
全力以赴:
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的大多数变体都有一个替换函数,因此您可能会将替换硬编码到表达式中,因此在服务器端执行此操作。如果您希望它可以重复使用,您可能需要以下内容:
private static Expression<Func<LeadGridViewModel,String>> leadGridTransform =
(lead) => lead.CompanyName == null ? "", lead.CompanyName.Replace(' ','\0').Replace.... ;
然后您可以在Queryable表达式中使用它:
var results = result.GroupBy(leadGridTransform)....
这里使用了三元运算符,因为它避免了昂贵的服务器端合并操作。
查找特定字符串的所有记录: 在这里,您真的想要反转比较并找到与给定字符串等效的所有字符串,然后查询包含在其中的公司名称。因此,假设db.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))...
注意:对于比较的反转,这些方法都有其自身的局限性。在第一个实现中,数据库越大,构建可用分组的速度就越慢。对于第二个实现,名称具有的分隔符越多,构建排列所需的时间就越多(指数式)。如果您对替换进行硬编码,那么这可以在服务器端完成,从而避免这些限制。