使用IEqualityComparer查找记录

时间:2012-11-05 14:05:26

标签: c# linq 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, '\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,而是使用相等比较器来包含特殊字符替换。

2 个答案:

答案 0 :(得分:1)

你做不到。用于调用(甚至是{内部使用的代码)IEqualityComparison的代码不能转换为SQL查询,因为IEqualityComparison中的代码是编译的,而不是使用Expression个对象构建的。

答案 1 :(得分:1)

  1. 在linqToDatabase查询中使用IEqualityComparer: 除非您能够以提供者可以翻译的形式封装逻辑,否则必须在本地完成。从您使用此问题的路线我认为提供商无法处理它。所以我们可以在本地做以下事情:

    1. 全力以赴:

      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();
      
    2. 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();
      
    3. 流式传输结果

      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();
      
    4. 注意:sql的大多数变体都有一个替换函数,因此您可能会将替换硬编码到表达式中,因此在服务器端执行此操作。如果您希望它可以重复使用,您可能需要以下内容:

      private static Expression<Func<LeadGridViewModel,String>> leadGridTransform = 
          (lead) => lead.CompanyName == null ? "", lead.CompanyName.Replace(' ','\0').Replace.... ;
      

      然后您可以在Queryable表达式中使用它:

      var results = result.GroupBy(leadGridTransform)....
      

      这里使用了三元运算符,因为它避免了昂贵的服务器端合并操作。

    5. 查找特定字符串的所有记录: 在这里,您真的想要反转比较并找到与给定字符串等效的所有字符串,然后查询包含在其中的公司名称。因此,假设db.Leads是LeadGridViewModel的表,因此我们可以使用比较器

      1. 隐式反转:

        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))...
        
      2. 显式反转:

        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))...
        
    6. 注意:对于比较的反转,这些方法都有其自身的局限性。在第一个实现中,数据库越大,构建可用分组的速度就越慢。对于第二个实现,名称具有的分隔符越多,构建排列所需的时间就越多(指数式)。如果您对替换进行硬编码,那么这可以在服务器端完成,从而避免这些限制。

相关问题