2010-06-15 52 views
0

我在我的应用程序中有Canine和CanineHandler对象。 CanineHandler对象具有一个PersonID(它引用一个完全不同的数据库),一个EffectiveDate(它指定一个处理程序何时以canine开始)以及一个对Canine(CanineID)的FK引用。在nhibernate中选择最新的组

给定一个特定的PersonID,我想找到他们目前负责的所有犬。 (简化)查询我会在SQL中使用将是:下面添加映射文件:

Select Canine.* 
    from Canine 
     inner join CanineHandler on(CanineHandler.CanineID=Canine.CanineID) 
     inner join 
      (select CanineID,Max(EffectiveDate) MaxEffectiveDate 
       from caninehandler 
       group by CanineID) as CurrentHandler 
      on(CurrentHandler.CanineID=CanineHandler.CanineID 
       and CurrentHandler.MaxEffectiveDate=CanineHandler.EffectiveDate) 
    where [email protected] 

编辑

<class name="CanineHandler" table="CanineHandler" schema="dbo"> 
    <id name="CanineHandlerID" type="Int32"> 
     <generator class="identity" /> 
    </id> 
    <property name="EffectiveDate" type="DateTime" precision="16" not-null="true" /> 
    <property name="HandlerPersonID" type="Int64" precision="19" not-null="true" /> 
    <many-to-one name="Canine" class="Canine" column="CanineID" not-null="true" access="field.camelcase-underscore" /> 
</class> 

<class name="Canine" table="Canine"> 
    <id name="CanineID" type="Int32"> 
     <generator class="identity" /> 
    </id> 
    <property name="Name" type="String" length="64" not-null="true" /> 
    ... 
    <set name="CanineHandlers" table="CanineHandler" inverse="true" order-by="EffectiveDate desc" cascade="save-update" access="field.camelcase-underscore"> 
     <key column="CanineID" /> 
     <one-to-many class="CanineHandler" /> 
    </set> 
    <property name="IsDeleted" type="Boolean" not-null="true" /> 
</class> 

我还没试过,但我猜我能做到这在HQL中。我没有必须在HQL中写任何东西,所以我最终必须解决这个问题,但是我的问题是,我是否可以使用条件/子查询对象来执行此子查询。

我得到尽可能创建以下超脱标准:

DetachedCriteria effectiveHandlers = DetachedCriteria.For<Canine>() 
       .SetProjection(Projections.ProjectionList() 
        .Add(Projections.Max("EffectiveDate"),"MaxEffectiveDate") 
        .Add(Projections.GroupProperty("CanineID"),"handledCanineID") 
       ); 

,但我无法弄清楚如何做内部联接。如果我这样做:

Session.CreateCriteria<Canine>() 
    .CreateCriteria("CanineHandler", "handler", NHibernate.SqlCommand.JoinType.InnerJoin) 
    .List<Canine>(); 

我得到一个错误“无法解析属性:CanineHandler的:OPS.CanineApp.Model.Canine”。显然我错过了一些东西,但从文档中我得到的印象是应该返回一个有处理程序的Canine列表(可能带有重复项)。直到我可以使这项工作,添加子查询不会工作...

我发现了类似的问题,如Only get latest results using nHibernate,但没有一个答案真的似乎适用于那种直接的结果我'寻找。

任何帮助或建议,非常感谢。

+1

嗯,这是一个小有点难以在没有映射的情况下正确回答 - 我通过使用子查询解决了类似的问题 - 见14.8。 nhibernate参考中的独立查询和子查询 – bernhardrusch 2010-06-16 13:54:01

+0

第一个查询看起来不太正确 - 它不会获取当前正在处理的所有狗,而是最近处理的狗。只有当同一天开始处理多只狗时,才会返回多个结果。 – mdma 2010-06-18 01:07:06

+0

SQL查询起作用。它返回一个CanineID列表和最近处理程序分配给狗的日期(即{(1,2010.01.01),(2,2010.03.05),...}。 第二个查询匹配处理程序记录我应该提到,在实践中,EffectiveDate和CanineID唯一标识了CanineHandler中的一行 我没有在该表上强制执行此替代键约束,但即使返回了两行CanineID和Date对,查询仍然可以工作 – Kendrick 2010-06-18 17:24:41

回答

1

在上次检查时,加入到您的示例中的派生表中,CurrentHandler在HQL中不起作用。尝试映射一个存储过程,可以让你编写任何你喜欢的SQL。下面是一个映射的存储过程是什么样子:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="S2.BP.NHSupport" namespace="S2.BP.Model"> 
    <sql-query name="spGoGetMyDogs" callable="true"> 
    <return-scalar column="PersonID" type="int" /> 
    exec spGoGetMyDogs @PersonID=:personID 
    </sql-query> 
</hibernate-mapping> 

然后,你可以通过你的是PersonID参数,并已NH,象这样一个变压器的结果映射回你的对象:

public IEnumerable<Canine> LetTheDogsOut(int personID) { 
    return nhSession.GetNamedQuery("spGoGetMyDogs") 
    .SetInt32("personID", personID) 
    .SetResultTransformer(Transformers.AliasToBean(typeof(Canine))) 
    .List<Canine>(); 
} 
+0

通过Hibernate文档,我注意到它有一个自然ID的概念,似乎没有转移到nHibernate。我试着用HQL来做,并且如你所说,发现似乎不可能。我最终只是在存储库中嵌入了一条SQL语句,但可能会按照您的建议切换到SP。感谢您的回应! – Kendrick 2010-06-23 13:20:21