【问题标题】:Write Round in NHibernate criteria在 NHibernate 标准中写轮次
【发布时间】:2014-10-16 14:29:29
【问题描述】:

我需要在 NHibernate Criteria 中将其写为 投影

subAlias_不是_根别名,所以{alias}不能替换正确的sql别名,而我的问题是查询的其他部分使得subAlias在生成的sql中不一样

ROUND(alias.Property / parameterValueFromMethodParameter + ", 0) 
   * parameterValueFromMethodParameter2 AS SQLAlias

这是我走了多远(偏离):

.Add(Projections.SqlFunction(new VarArgsSQLFunction("(", "/", ")")
     , NHibernateUtil.Int32
     , Projections.SqlFunction("round"
          , NHibernateUtil.Decimal
          , Projections.Property("subAlias.Property"))), "SQLAlias"))

这会产生以下 SQL 代码:

ROUND( subAlias3(4).Property
            )AS y1_

有没有人有过这样的预测经验? 我发现这个patch我休眠了,但似乎没有实现。

【问题讨论】:

  • 我试图改进您的格式,但您应该仔细检查您粘贴的代码 sn-ps。他们似乎没有工作......
  • 哦,感谢格式化 :) 这只是示例“伪”代码,而不是工作代码...

标签: nhibernate criteria projection


【解决方案1】:

如果我正确理解您的示例,最简单的解决方案是使用 SQL 投影:

// the parameterValueFromMethodParameter 
// and parameterValueFromMethodParameter2 
var computationParams = new object[] {2, 4}; // just an example numbers

// SQL To be generated
// see that here we work with COLUMN name, not property
var sqlSnippet = " ( ROUND({{alias}}.ColumnName / {0}, 0) * {1} ) AS computed ";

// put that all together
var projectSql = string.Format(sqlSnippet, computationParams);

// IProjection
var projection = Projections.SqlProjection(projectSql, new string[0], new IType[0]);

// add it to SELECT clause
criteria.SetProjection(Projections.ProjectionList()
           .Add(projection)
           ...
         );

应该可以的...

【讨论】:

  • 我的问题是 {alias} 不是根别名,它是另一个表的别名。所以我无法让 NH 用正确生成的 sql 别名替换 {alias}。我已经更新了问题。
  • 嗯,基本上,这超出了标准的 ORM。一种方法可能是为非根表(例如 notRoot3_)依赖几乎总是相同的别名。或者使用过滤器创建自定义 SQL 子查询 {alias}.ID... 但无论如何。这很难被标记为 ORM 查询的标准要求......对不起......
  • 这远非标准!我同意,但我们有一个基于标准的大型搜索查询,它会根据用户选择添加别名,以便能够搜索不同的字段。所以即使不标准,我们也需要解决:)
  • 改变除以和乘以多少?这些可以被视为常量吗?如果是...您可以创建新的映射。您可以拥有一个新属性,并在该非根实体上进行此计算。那将是用formula="" 只读定义的,然后你可以很容易地查询它。但又一次。实际上,您可以使用 Your OWN SELECT... subselect 将其注入到 SELECT 子句中。您可以使用根的 {alias}.ID 以确保选择了正确的行。据我所知,没有其他办法......
  • 我试图在不向 nhibernate 添加任何代码的情况下解决这个问题。但最后我变得务实,为 IProjection 写了另一个 ToSqlString。这很好用。感谢您对 Radim 的帮助!
【解决方案2】:

我通过编写自己的 SQL IProjection 解决了这个问题。在this example 的帮助下。

 public SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
    {
        string replacedString = Regex.Replace(
            this.sql, 
            @"{([a-zA-Z_]((\.)?[a-zA-Z0-9_])*)}", 
            m =>
                {
                    ICriteria critter = criteria.GetCriteriaByAlias(m.Groups[1].Value);
                    if (critter != null)
                    {
                        return criteriaQuery.GetSQLAlias(critter);
                    }

                    return m.Groups[0].Value;
                });

        return new SqlString(replacedString);
    }

所以现在我可以做(在 SqlGroupProjection 中):

ROUND({subAlias}.XCoord / " + aggregationSize + ", 0) * " + aggregationSize + " AS SQLAlias

还有一些其他尝试扩展 (N)Hibernate 以处理原始 SQL 问题中的此别名:

Expression.Sql should support aliases other than {alias}
Support for referencing non-root entities in Criteria SQL expressions

【讨论】:

    猜你喜欢
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多