QueryBver上的GroupBy SqlFunction

时间:2012-05-29 15:00:53

标签: c# sql nhibernate queryover

我有一个使用

获取的所有不同帐户名称前缀(a-z)的列表
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))));

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

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

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

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

修改这是我尝试的但是我收到了以下错误

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

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

          );

3 个答案:

答案 0 :(得分:4)

如果其他所有方法都失败,您可以使用Projections.SqlGroupProjection来完成!

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

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

答案 1 :(得分:3)

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

执行常规组
var sqlout= (from acc in this.SessionManager.GetActiveSession().Query<Account>()
          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上运行

答案 2 :(得分:3)

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

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

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