0

私はこのデータベーススキーマを持っているとしましょう

[User] -1----n-> [Resource] -1----n-> [ResourceVersion]

そして、ユーザー名によるユーザーの1つのデータベースラウンドトリップでNhibernateを使用してこれを選択したいのですが、将来のresourceVersionsを選択すると機能します。Futuresを使用して1回の往復でコレクションのコレクションを水和する方法は? 私は HQL よりも QueryOver または Criteria を好みます。nHibernate 4.0 を使用しています。

public virtual User GetUserResources(string username)
  using (ISession session = GetSession())
  {
    Resource resAlias = null;           
    User userAlias = null;

    var result = session.QueryOver(() => userAlias)
     .JoinQueryOver(x => x.Resources, () => resAlias)
     .JoinQueryOver(() => resAlias.Versions)
     .Where(() => userAlias.Login == username)
     .Future<User>(); //THIS DOESNT WORK


      var user = session.QueryOver<User>()
       .Fetch(x => x.Resources).Eager
       .Where(x => x.Login == username)
       .SingleOrDefault<User>();//with this i can select user and resources

      return user;
   }

マッピング:

USER:
<class name="User" table="[User]">
  <id name="Id" type="Int32">
    <generator class="identity" />
  </id>

  <property name="Name">
    <column name="Name" sql-type="varchar(100)" />
  </property>

  <property name="Email">
    <column name="Email" sql-type="varchar(255)" />
  </property>

  <property name="Login">
    <column name="Login" sql-type="varchar(50)" />
  </property>

  <property name="PasswordHash">
    <column name="PasswordHash" sql-type="varchar(100)" />
  </property>

  <property name="CreateDate">
    <column name="CreateDate" sql-type="datetime" />
  </property>

  <bag name="Resources" lazy="true" fetch="subselect" cascade="all-delete-orphan">
    <key column="UserResource"/>
    <one-to-many class="Resource" />
  </bag>
</class>

RESOURCE:
<class name="Resource" table="[Resource]" abstract="true">
  <id name="Id" type="Int64">
    <generator class="identity" />
  </id>

  <discriminator column="Type"
               not-null="true"
               type="String" />

  <bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="true" order-by="ActiveFrom DESC">
    <key column="ResourceId" not-null="true"/>
    <one-to-many class="Version"/>
  </bag>

  <subclass name="Resource1" discriminator-value="Res1" />

  <subclass name="Resource2" discriminator-value="Res2" />
</class>

VERSION:
<class name="Version" table="Version">

<id name="Id" type="long">
  <!--<column name="Id" sql-type="bigint"/>-->
  <generator class="identity" />
</id>
...
<many-to-one name="Resource"
             class="Resource"
             column="ResourceId"/>

 <property name="ActiveFrom">
   <column name="ActiveFrom" sql-type="datetime" />
 </property>

 <property name="ActiveTo">
   <column name="ActiveTo" sql-type="datetime"/>
 </property>
...

Visual Studio で intelli トレースに従って実行されるクエリは次のとおりです。

SELECT this_.Id AS Id0_1_ , 
   this_.Name AS Name0_1_ , 
   this_.Email AS Email0_1_ , 
   this_.Login AS Login0_1_ , 
   this_.PasswordHash AS Password5_0_1_ , 
   this_.CreateDate AS CreateDate0_1_ , 
   resource2_.UserResource AS UserResource3_ , 
   resource2_.Id AS Id3_ , 
   resource2_.Id AS Id4_0_ , 
   resource2_.Type AS Type4_0_
FROM
   [User] this_ LEFT OUTER JOIN [Resource] resource2_
   ON this_.Id
      = 
      resource2_.UserResource
WHERE this_.Login    
        =
       @p0; 

@p0 は、メソッドに渡すユーザー名です。少し奇妙だと思うバージョンの兆候はまったくありません。

4

1 に答える 1

0

将来によって返される IEnumerable を反復することはないため、実行されることはありません。現在、NH 4.0 はありませんが、次の方法で動作する可能性があります

public virtual User GetUserWithResources(string username)
{
    using (ISession session = GetSession())
    {
      Resource resAlias = null;           

      return session.QueryOver<User>()
          .Where(user => user.Login == username)
          .Left.JoinQueryOver(x => x.Resources)
              .Left.JoinQueryOver(res => res.Versions)
          .TransformUsing(Transformers.DistinctRootEntity)
          .List<User>().SingleOrDefault();
    }
}
于 2015-02-10T12:52:42.373 に答える