2012-05-29 8 views
7

Tôi có một danh sách tất cả các tiền tố tên tài khoản riêng biệt (az) mà tôi có được sử dụnggroupby SqlFunction trên QueryOver

var accounts = this.SessionManager.GetActiveSession().QueryOver<Account>(); 

var q = accounts.Select(Projections.Distinct(
     Projections.SqlFunction("substring", 
           NHibernateUtil.String, 
           Projections.Property("Name"), 
           Projections.Constant(1), 
           Projections.Constant(1)))); 

Tuy nhiên những gì tôi muốn làm là thay vì trả lại một danh sách riêng biệt là nhóm các tiền tố và trở lại số lượng tài khoản bắt đầu bằng tiền tố đó, nhưng tôi không chắc chắn cách thực hiện một nhóm bằng cách sử dụng truy vấn vì nó không đơn giản như là LINQ chuẩn.

Lý do tôi đang sử dụng QueryOver và không truy vấn là vì một số lý do chức năng chuỗi con đang được thực hiện trong bộ nhớ chứ không phải trên máy chủ cơ sở dữ liệu.

Đây là cách tôi thường sẽ làm điều đó

var prefixes = (from acc in this.SessionManager.GetActiveSession().Query<Account>() 
       group acc by acc.Name.Substring(0, 1) 
       into grp 
       select new 
         { 
         Prefix = grp.Key, 
         Count = grp.Count() 
         }); 

Sửa Đây là những gì tôi đã cố gắng nhưng tôi nhận được lỗi sau

Không nhận dạng được gọi phương thức trong biểu SqlFunction ("chuỗi con ", NHibernateUtil.String, new [] {Property (" Name "), Constant (Convert (1)), Constant (Convert (1))})

var accounts = this.SessionManager.GetActiveSession().QueryOver<Account>().Select(
      Projections.Group<string>(x => Projections.SqlFunction("substring", NHibernateUtil.String, 
                 Projections.Property("Name"), Projections.Constant(1), 
                 Projections.Constant(1))), 
      Projections.Count<string>(x => Projections.SqlFunction("substring", NHibernateUtil.String, 
                 Projections.Property("Name"), Projections.Constant(1), 
                 Projections.Constant(1))) 

     ); 

Trả lời

4

Bạn có thể làm điều đó bằng cách sử dụng Projections.SqlGroupProjection nếu tất cả đều thất bại!

var accounts = _busDb.Session.QueryOver<QueueEntity>() 
     .Select(
      Projections.SqlGroupProjection(
       "SUBSTRING({alias}.Name, 1) as FirstChar", 
       "SUBSTRING({alias}.Name, 1)", 
       new[] {"FirstChar"}, 
       new[] {NHibernateUtil.String}), 
      Projections.Count("id")); 

Đối số đầu tiên là những gì được chọn trong lựa chọn, đối số thứ hai là những gì được nhóm lại theo, đối số thứ ba là tên của cột (s) được chọn, và đối số thứ tư là các loại dữ liệu đang được chọn.

+0

Chức năng chuỗi con cần thêm một tham số nhưng điều này giải quyết được vấn đề. Nhiều người cảm ơn – JConstantine

3

danh sách của bạn lớn bao nhiêu? Nếu nó ít hơn 1000 tôi sẽ thu thập danh sách mục từ sql máy chủ sau đó thực hiện nhóm thường xuyên của bạn bằng cách truy vấn đối với danh sách

var sqlout= (from acc in this.SessionManager.GetActiveSession().Query<Account>() 
      select new 
        { 
        Name = acc.Name, 
        col1= acc.col1 
        }).TolList(); 

và sau đó

var prefixes = (from acc in sqlout 
      group acc by acc.Name.Substring(0, 1) 
      into grp 
      select new 
        { 
        Prefix = grp.Key, 
        Count = grp.Count() 
        }); 

xâu chức năng sẽ làm việc ở đây từ chạy nó trên C# danh sách không phải trên máy chủ sql

+0

Hiện tại, chúng tôi đang xem danh sách có hơn 20 nghìn tài khoản. :( – JConstantine

3

Bạn đã cân nhắc loại bỏ nhu cầu truy vấn chuỗi con bằng cách lưu ký tự đầu tiên của tên trong một cột riêng biệt?

Giả sử bạn đang sử dụng SQL Server, bạn có thể biến nó thành cột được tính liên tục để tránh phải cập nhật mã chèn/cập nhật bảng.

Khả năng thêm chỉ mục chứa cột này cũng sẽ giúp bạn cải thiện hiệu suất truy vấn của mình.

+0

+1 Như một giải pháp lâu dài, đây có lẽ là cách chúng ta phải giải quyết vấn đề này. lí trí – JConstantine