如何使用to_char()在nhibernate查询中进行条件连接?

时间:2014-09-25 15:50:09

标签: .net oracle nhibernate queryover

我们有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 =&#39; Old&#39;时从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)"   />   

主要问题是先前的查询忽略&#34;和(this_.Source_Type =&#39; Old&#39;)&#34;并尝试使用OldOne进行连接,即使Source_Type!= Old和SOURCE_ID不是数字。不确定它是否只是Oracle的问题。

1 个答案:

答案 0 :(得分:1)

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

予。 HQL,笛卡尔积,自定义WHERE

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

  

可能会出现多个班级,导致产生笛卡尔积或“#34; cross&#34;加入。

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(旧的,新的)转换,但逻辑是明确的。我们肯定需要的是,映射将包含

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

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

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

小片段和引用:

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

(5)公式(可选):一个SQL表达式,用于定义计算属性的值。计算属性没有自己的列映射。

小片段和引用:

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

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

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

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

新的可以有一个明确的参考:

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

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

最后,通过此映射,我们的QueryOver应与标准JoinAlias ...

一起使用