2013-04-24 10 views
9

Liệu có cách nào để làm một truy vấn LINQ2SQL làm điều gì đó tương tự như sau:Trường hợp nhóm nhạy cảm trên nhiều cột

var result = source.GroupBy(a => new { a.Column1, a.Column2 }); 

hoặc

var result = from s in source 
      group s by new { s.Column1, s.Column2 } into c 
      select new { Column1 = c.Key.Column1, Column2 = c.Key.Column2 }; 

nhưng với bỏ qua trường hợp của các nội dung của các cột nhóm ?

+0

này không hoạt động? 'a => {Column1 = a.Column1.ToLower(), Column2 = a.Column2.ToLower()}' –

Trả lời

18

Bạn có thể vượt qua StringComparer.InvariantCultureIgnoreCase đến phương thức mở rộng GroupBy.

var result = source.GroupBy(a => new { a.Column1, a.Column2 }, 
       StringComparer.InvariantCultureIgnoreCase); 

Hoặc bạn có thể sử dụng ToUpperInvariant trên mỗi trường như được đề xuất bởi Hamlet Hakobyan khi nhận xét. Tôi khuyên bạn nên ToUpperInvariant hoặc ToUpper thay vì ToLower hoặc ToLowerInvariant vì nó được tối ưu hóa cho mục đích so sánh có lập trình.

+6

Một 'StringComparer' không thể so sánh các cá thể của các kiểu vô danh, chỉ các chuỗi. Cần thực hiện một phép so sánh mới (xem câu trả lời của Bill B) –

+0

@DiegoMijelshon nếu 'Column1' và' Column2' là kiểu 'chuỗi', sau đó' GroupBy (a => a.Column1 + a.Column2, StringComparer.InvariantCultureIgnoreCase) ' nên làm việc – fubo

5

tôi không thể có được giải pháp NaveenBhat của để làm việc, nhận được một lỗi biên dịch:

The type arguments for method 'System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func, System.Collections.Generic.IEqualityComparer)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Để làm cho nó làm việc, tôi thấy nó dễ nhất và rõ ràng nhất để xác định một lớp mới để lưu trữ các cột chính của tôi (GroupKey) , sau đó là một lớp riêng biệt triển khai IEqualityComparer (KeyComparer). sau đó tôi có thể gọi

var result= source.GroupBy(r => new GroupKey(r), new KeyComparer()); 

lớp Các KeyComparer không so sánh chuỗi với Comparer InvariantCultureIgnoreCase, vì vậy thanh danh cho NaveenBhat đã chỉ cho tôi đi đúng hướng.

phiên bản đơn giản hóa của các tầng lớp của tôi:

private class GroupKey 
{ 
    public string Column1{ get; set; } 
    public string Column2{ get; set; } 

    public GroupKey(SourceObject r) { 
     this.Column1 = r.Column1; 
     this.Column2 = r.Column2; 
    } 
} 

private class KeyComparer: IEqualityComparer<GroupKey> 
{ 

    bool IEqualityComparer<GroupKey>.Equals(GroupKey x, GroupKey y) 
    { 
     if (!x.Column1.Equals(y.Column1,StringComparer.InvariantCultureIgnoreCase) return false; 
     if (!x.Column2.Equals(y.Column2,StringComparer.InvariantCultureIgnoreCase) return false; 
     return true; 
     //my actual code is more complex than this, more columns to compare 
     //and handles null strings, but you get the idea. 
    } 

    int IEqualityComparer<GroupKey>.GetHashCode(GroupKey obj) 
    { 
     return 0.GetHashCode() ; // forces calling Equals 
     //Note, it would be more efficient to do something like 
     //string hcode = Column1.ToLower() + Column2.ToLower(); 
     //return hcode.GetHashCode(); 
     //but my object is more complex than this simplified example 

    } 
} 
+0

Bạn có chắc chắn rằng bạn không chỉ cần gõ 'StringComparison.InvariantCultureIgnoreCase' (mà là một enum) thay vì' StringComparer.InvariantCultureIgnoreCase' (là một lớp)? –

+0

Bạn đúng, @dav_i, đó là nguồn gốc của "không thể chuyển đổi từ 'System.StringComparison' ..." lỗi tôi nhận được. Tuy nhiên, ngay cả khi tôi không phạm sai lầm đó thì một lỗi biên dịch khác đã bị ném. Tôi đã cập nhật câu trả lời của mình để phản ánh vấn đề gặp phải và lý do cho giải pháp này. Cảm ơn! –

1

tôi đã cùng một vấn đề nhóm bởi các giá trị của các đối tượng DataRow từ một Table, nhưng tôi chỉ sử dụng ToString() trên đối tượng DataRow để vượt qua các trình biên dịch vấn đề, ví dụ

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"].ToString(), 
    StringComparer.InvariantCultureIgnoreCase) 

thay vì

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"], 
    StringComparer.InvariantCultureIgnoreCase)