我们有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的问题。
答案 0 :(得分:1)
在这种情况下通常有两种方式。
如果我们的 NewOne 和 OldOne 之间没有映射,我们可以从强大的功能集中获取(一如既往) NHibernate的。
可能会出现多个班级,导致产生笛卡尔积或“#34; cross&#34;加入。
from Formula, Parameter
from Formula as form, Parameter as param
to_char
,因为Oracle8iDialect
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" />
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
...