【问题标题】:How to make conditional join in nhibernate queryover using to_char()?如何使用 to_char() 在 nhibernate 查询中进行条件连接?
【发布时间】:2014-11-20 11:27:00
【问题描述】:

我们有 2 个表/类,我们称它们为 NewOne 和 OldOne。 OldOne 的 Id 类型为 int,NewOne 具有 OldOne 的属性 OldValues 磁带和映射的字符串 SourceType(数据库为 Oracle):

<many-to-one name="OldValues" column="SOURCE_ID"   />
<property name="SourceType " column="Source_Type " type="AnsiString" />

我们想在 SourceType='Old' 时从 NewOne 和 OldOne 获取数据,但问题是 OldOne 表的 ID 列是数字,Source_Id 列是 varchar 存储其他类型的 id,如名称等。我们无法更改类型ID 既不是 Source_ID 列。使用 to_char() 函数可以在 sql 中轻松完成这种连接:

left outer join OldOne old_     
on this_.SOURCE_ID = to_char(old_.ID)
and (this_.Source_Type = 'Old') 

但我在 QueryOver 中找不到等效的 to_char。下面是有条件连接但没有 to_char() 的版本:

 OldOne OldOneAlias = null;
 NewOne NewOneAlias = null;
 return this.ActiveSession.QueryOver<NewOne>(() => NewOneAlias)
                .JoinAlias(r => r.OldValues,
                           () => OldOneAlias,
                           JoinType.LeftOuterJoin,
                           Restrictions.Eq(
                               Projections.Property(() => NewOneAlias.SourceType), "Old")) 

有什么方法可以使用 QueryOver 创建带有 to_char 的查询?

更新:
我在这里找到了一个有点丑陋的解决方案:"Safe" TO_NUMBER() 并且在更改我的映射后一切正常:

    <many-to-one name="OldValues" formula="COALESCE(TO_NUMBER(REGEXP_SUBSTR(SOURCE_ID, '^\d+')), 0)"   />   

主要问题是之前的查询忽略了“and (this_.Source_Type = 'Old')”,即使 Source_Type != Old 和 SOURCE_ID 不是数字,也会尝试与 OldOne 连接。不确定它是否只是 Oracle 的问题。

【问题讨论】:

  • 我认为这并不容易——QueryOver 加入映射的关联,因此您可以尝试将many-to-one 映射更改为使用to_char() 加入。 Oracle 是否支持计算列?如果是这样,您可以使用 to_char 创建一个计算列并映射 that

标签: .net oracle nhibernate queryover


【解决方案1】:

在这种情况下,通常有两种方法。

我。 HQL、笛卡尔积、自定义 WHERE

如果我们的 NewOneOldOne 之间没有映射,我们可以从强大的功能集 (一如既往) NHibernate。

可能会出现多个类,从而导致笛卡尔积或“交叉”连接。

from Formula, Parameter
from Formula as form, Parameter as param

(small snippet)

protected virtual void RegisterFunctions()
{
    ...
    RegisterFunction("to_char", new StandardSQLFunction("to_char"
                              , NHibernateUtil.String));

在我们的工具带中有这个 - 这种查询应该可以工作:

var session = ... // get your session
// HQL
var hql = 
  // firstly use SELECT to define the resultset columns
  // - to use Transformer, do not forget to add the AS statement
  @"SELECT n.ID AS ID " +
  // the trick with a CROSS join
  " FROM NewOne AS n, OldOne AS o " +
  // here should be some OR handling if we want to result
  // LEFT style join, i.e. if oldValue is null (skipped below)
  " WHERE n.SourceId = to_char(o.ID) ";

var query = session.CreateQuery(hql);
// result transfomer if we do not want to get List<Object[]>
// NewOneDTO could have property set from both old and new
query.SetResultTransformer(Transformers.AliasToBean<NewOneDTO>());
// here we go
var list = query.List<NewOneDTO>();

注意:不完全确定应该用 to_char (old, new) 转换哪个,但逻辑很清楚。我们肯定需要的是映射将包含

<property name="SourceId" column="SOURCE_ID"   />

二。 formula=""property-ref="" 映射

正如Andrew Whitaker 已经在评论中指出的那样,我们也可以调整映射。但是我们甚至不需要数据库引擎的特殊功能(例如计算列),因为 NHibernate 为我们提供了:

小sn-p并引用:

<property
    ...
    formula="arbitrary SQL expression"  (5)

(5) formula(可选):定义计算属性值的 SQL 表达式。计算属性没有自己的列映射。

小sn-p并引用:

<many-to-one
    ...
    property-ref="PropertyNameFromAssociatedClass"     (7)

(7) property-ref:(可选)与此外键连接的关联类的属性名称。如果未指定,则使用关联类的主键。

在我们不断增长的工具带中拥有这些,我们可以在旧工具上引入映射:

<property name="ConvertedSourcId" formula="to_char(ID)" 
                                  insert="false" update="false" />

并且 new 可以有明确的引用:

<many-to-one name="OldValue" column="SOURCE_ID" property-ref="ConvertedSourcId"
                                  insert="false" update="false" />

在这两种情况下,我们都需要 readonly 解决方案。但是对于获取旧数据来说,就超出预期了,不是吗?

最后,通过这个映射,我们的QueryOver 应该可以与标准的JoinAlias 一起使用...

【讨论】:

  • 我已经尝试过使用 formula="to_char(ID)" 的解决方案,但不幸的是,由于某种原因,我得到了“ORA-01747: invalid user.table.column, table.column, or column specification " 即使我已复制粘贴了确切的 Id 列名(尝试使用其他列但同样的错误),也会出现错误。我认为问题可能出在 QueryOver 生成查询的方式上:left external join OldOne old_ on this_.SOURCE_ID = old_。和 (this_.Source_Type = 'Old') 。
  • 我建议,逐步测试它。确保它正在加载使用公式映射的列。然后确保,如果您加载新的,它的多对一引用已填充(该属性引用正在工作)。如果这些能成功工作,我会说 NHibenrate 将设法在 QueryOver 中使用它……我正在使用 SQL Server,对于 ORA 错误的弱帮助,我深表歉意。但是无效的用户列...似乎公式内部的定义不正确(尝试用大括号括起来)
  • 我已经进行了更多测试,并且您的映射有效,但由于某种原因,我的 QueryOver 无法与此类“计算”字段进行连接。我还意识到问题在于“和 (this_.Source_Type = 'Old')" 没有太大作用,因为每次 this_.SOURCE_ID 没有编号时查询仍然会失败。要解决此问题,我在这里找到了解决方法:stackoverflow.com/questions/4486949/safe-to-number 并仅更改了 NewOne 的映射(问题中附加的代码)。我接受你的回答,因为我最终使用了公式道具,但我希望它也包括我的解决方法。
  • 我建议:把你的答案放在这里。如果你的答案比我的好,请接受你的。这将对其他人有更多帮助......无论如何,祝 NHibernate 好运;)惊人的工具
  • 更新的问题也是很好的解决方案。简单 - 对其他人可见。很棒
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多