3

我使用以下 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,而是使用相等比较器来包含特殊字符替换。

4

2 回答 2

1

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

于 2012-11-05T14:09:35.870 回答
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. 去查查看()

      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();
      

    注意:大多数 sql 变体都有一个替换功能,因此您可能会将替换硬编码到表达式中,从而在服务器端执行此操作。如果您希望它可重用,您将需要类似以下内容:

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

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

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

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

  2. 查找某个字符串的所有记录:在这里,您确实想要反转比较并找到与给定字符串等效的所有字符串,然后查询其中包含的公司名称。所以假设 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))...
      

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

于 2012-11-05T18:28:36.480 回答