QueryOver上的GroupBy SqlFunction

我有一个我使用的所有不同帐户名称前缀(az)的列表

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

但是,我想要做的不是返回一个不同的列表,而是将前缀分组并返回以该前缀开头的帐户数,但我不确定如何使用查询来执行组,因为它不像标准那样简单LINQ。

我使用QueryOver而不是Query的原因是因为某些原因,子串函数正在内存中执行而不是在数据库服务器上执行。

这就是我通常会这样做的方式

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

编辑这是我尝试但我收到以下错误

表达式中无法识别的方法调用SqlFunction(“substring”,NHibernateUtil.String,new [] {Property(“Name”),Constant(Convert(1)),Constant(Convert(1))})

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

如果其他所有方法都失败了,你可以使用Projections.SqlGroupProjection来做到这一点!

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

第一个参数是select中选择的内容,第二个参数是分组的内容,第三个参数是所选列的名称,第四个参数是所选数据的类型。

你的名单有多大? 如果它小于1000,我会从sql server收集项目列表,然后通过查询列表执行常规组

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

然后

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

子串函数在这里工作,因为它在c#list上运行而不是在sql server上运行

您是否考虑通过将名称的第一个字符存储在单独的列中来消除对子字符串查询的需求?

假设您使用的是SQL Server,可以将其设置为持久计算列,以避免更新插入/更新表的代码。

添加包含此列的索引的function还可以帮助您提高查询性能。