2009-08-20 4 views
1

私はクラスTaskを持っていて、そこからいくつかのコードをロードして実行するdllというTaskLibraryというプロパティを持っています。したがって、どのタスクにも1つのライブラリがありますが、どのライブラリも多くのタスクを持つことができます。私の問題は、タスクのライブラリプロパティがnullでないことを確認するための私のテストが失敗していることです(私のテストになるかもしれません)。NHibernateとNUnitを使って1対多のrealtionshipをテストするのに役立ちます

public class Task 
{ 
    public virtual int TaskId {get;set;} 
    public virtual string Locked {get;set;} 
    public virtual int Status {get;set;} 
    public virtual TaskLibrary Library {get;set;} 
} 

public class TaskLibrary 
{ 
    public virtual int LibraryId {get;set} 
    public virtual string Name {get;set;} 
    public virtual string Description {get;set;} 
    public virtual byte[] Dll {get;set} 
    public virtual IEnumerable<Task> Tasks {get;set;} 
} 

私のNHibernateのマッピングは次のようになります。:MSSQL2000データベース内

[TestFixture] 
public class TaskRepositoryFixture 
{ 
    private ISessionFactory _sessionFactory; 
    private Configuration _configuration; 

    private readonly Task[] _tasks = new[] 
     { 
      new Task {Id = 1, Status = 1, Locked = 0, Library = new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}}, 
      new Task {Id = 2, Status = 1, Locked = 0, Library = new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}}, 
      new Task {Id = 3, Status = 1, Locked = 0, Library = new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}}, 
      new Task {Id = 4, Status = 1, Locked = 0, Library = new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}}, 
      new Task {Id = 5, Status = 1, Locked = 0, Library = new TaskLibrary { Id =3, Description = "Test Library 3", Name = "Tast3.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}}, 
     }; 

    private readonly TaskLibrary[] _libraries = new[] 
     { 
      new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")}, 
      new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")}, 
      new TaskLibrary { Id =3, Description = "Test Library 3", Name = "Tast3.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")} 
     }; 

    private void CreateInitialData() 
    { 
     using (ISession session = _sessionFactory.OpenSession()) 
     using (ITransaction transaction = session.BeginTransaction()) 
     { 
      foreach (var lib in _libraries) 
       session.Save(lib); 

      foreach (var task in _tasks) 
       session.Save(task); 

      transaction.Commit(); 
     } 
    } 


    [TestFixtureSetUp] 
    public void TestFixtureSetUp() 
    { 
     _configuration = new Configuration(); 
     _configuration.Configure(); 
     _configuration.AddAssembly("DistPollAutoTasksShared"); 
     _sessionFactory = _configuration.BuildSessionFactory(); 
    } 

    [SetUp] 
    public void SetupContext() 
    { 
     new SchemaExport(_configuration).Execute(false, true, false, false); 
     CreateInitialData(); 
    } 

    [Test] 
    public void CanGetLibraryFromTask() 
    { 
     ITaskRepository repository = new TaskRepository(); 
     var fromDb = repository.GetById(_tasks[0].Id); 
     Assert.IsNotNull(fromDb.Library); 
     Assert.IsNotNull(fromDb.Library.Dll); 
    } 
    } 

そして、タスクテーブル:

<class name="Task"> 
    <id name="Id" column="TaskId" type="Int32" unsaved-value="-1"> 
     <generator class="identity"/> 
    </id> 
    <property name="Locked" column="Locked"/> 
    <property name="Status" column="Status"/> 
    <many-to-one name="Library" class="TaskLibrary" fetch="join"/> 
    </class> 
    <class name="TaskLibrary"> 
    <id name="Id" column="LibraryId"> 
     <generator class="identity"/> 
    </id> 
    <property name="Name"/> 
    <property name="Description"/> 
    <property name="Dll"/> 
    <set name="Tasks" lazy="true"> 
     <key column="LibraryId"/> 
     <one-to-many class="Task"/> 
    </set> 
    </class> 

私のテストクラスは次のようになります私のクラスには、効果的に、このですこれはです:

CREATE TABLE [dbo].[Tasks](
    [TaskId] [int] IDENTITY(1,1) NOT NULL, 
    [TaskLibrary] [int] NOT NULL, 
    [Status] [int] NOT NULL, 
    [Locked] [int] NOT NULL 
) 

あなたがまだ私と一緒にいるなら...

私のタスククラスからは、ライブラリプロパティのTaskLibraryクラスのインスタンスが必要です。また、私がライブラリ自体で作業している場合、そのライブラリを使用しているすべてのタスクのIEnumerableを遅延して取得できるようにしたいと考えています。しかし、私はテストを実行したとき、私はこのエラーを取得:

TestCase 'DistPollAutoTasksShared.Tests.TaskRepositoryFixture.CanGetLibraryFromTask' 
failed: NHibernate.LazyInitializationException : Could not initialize proxy - no Session. 
    at NHibernate.Proxy.AbstractLazyInitializer.Initialize() 
    at NHibernate.Proxy.AbstractLazyInitializer.GetImplementation() 
    at NHibernate.Proxy.Poco.Castle.CastleLazyInitializer.Intercept(IInvocation invocation) 
    at Castle.DynamicProxy.AbstractInvocation.Proceed() 
    at TaskLibraryProxy2bd44073e90f47298039abfbfda11492.get_Dll() 

これは、私はNHibernateはを使用したのは初めてなので、私はまだ学んでいます。私は本当に基礎の基礎を身につけたいと思っています。そのときまで私はここで立ち往生しています。助け、提案、資料の読んだり(私はthis question'sの提案や他のものすべてを読んだことがあります)

EDIT:

"参加" =フェッチ変更した後、私はTaskクラスから必要な機能を取得しています。

[Test] 
    public void CanGetTasksByLibrary() 
    { 
     ITaskLibraryRepository repository = new TaskLibraryRepository(); 
     var fromDb = repository.GetById(_libraries[0].Id).Tasks; 

     Assert.IsNotNull(fromDb); 
     Assert.True(fromDb.Count() == 2, "Cannot get IEnumerable<Task> from TaskLibrary"); 
    } 

しかし、アサーションは(私が行ったすべての変更を反映するために、上記のコードを更新しました)このエラーで失敗します。しかし、私はTaskLibraryクラスのタスクのプロパティのための別のテストを追加しました:

TestCase 'DistPollAutoTasksShared.Tests.TaskLibraryRepositoryFixture.CanGetTasksByLibrary' 
failed: 
    Cannot get IEnumerable<Tasks> from TaskLibrary 
    Expected: True 
    But was: False 
+1

これは、セッションが開いている間に遅延ロードしかできないためです。これは、再帰的に発行されているたくさんのselect文で終わる可能性があるので、TaskLibrary.Tasksを熱心に読み込むことは望ましくありません。 @ドットジョー、右。 – dotjoe

+0

だから私はlazy = "true"に設定しましたが、それでも例外はスローされます。だから、私は怠惰な読み込みがどのように働くのか理解してはいけません。 – scottm

+0

基本的に遅延読み込みは、(仮想プロパティを使用して)pocoを拡張することによって機能し、プロパティの1つにアクセスすると、ロードされたセッションを使用しようとします。セッションが終了した場合、エラーが発生します。したがって、あなたの場合、タスクはタスクにアクセスしようとする前に開いて閉じています。 – dotjoe

答えて

1
<many-to-one name="Library" class="TaskLibrary" fetch="join" /> 

これは、すべての選択上のライブラリに参加するでしょう。

<many-to-one name="Library" class="TaskLibrary" lazy="false" /> 

これは、ライブラリに対して個別の選択を熱心に実行します。

これ以外の場合は、fetch = "select"(デフォルト)を設定するだけで、ライブラリを遅延読み込みします。

http://ayende.com/Blog/archive/2009/04/09/nhibernate-mapping-ltmany-to-onegt.aspx

http://nhibernate.info/doc/nh/en/index.html#collections-lazy

+0

遅延属性とフェッチ属性の違いは何ですか? – scottm

+0

はい、多対1にlazy = "false"を設定するだけで、すぐに別のselect文を発行します。 fetch = "join"を設定すると、怠惰な属性は意味がないと思います...しかし、それは100%ではありません。 – dotjoe

+0

私は理解しています。ありがとう! – scottm

0

マッピングでLazy = "false"を設定しようとしましたか? http://code-redefined.blogspot.com/2007/07/hibernate-lazy-fetch-problems-could-not.html

+0

また、処理している作業単位をチェックしてください。各アクセスが独自のトランザクションでラップされている場合は、セッションなしエラーが発生する可能性があります。これは例を参照してください:http://stackoverflow.com/questions/345705/hibernate-lazyinitializationexception-could-not-initialize-proxy –

+0

私は今やったが、私は同じ例外があります。 TaskLibraryクラスからTasksの読み込みを遅延させたいのですが。 – scottm

0

要件は、オブジェクトがどのようにマッピングされるかをドライブする必要があり、テストのためのマッピングを変更いけません。 リポジトリメソッドは、データベースからフェッチした後にセッションを終了しています。テストメソッド全体のセッションを開いたままにする必要があります。 これを行う方法を理解するには、セッションの管理方法を教えてください。それらはトランザクション/スレッドローカルに結びついていますか?

+0

それは私がそれを理解する方法ではありません。テストを最初に作成してコードを作成する必要があります(テストの最初の実行に失敗する)。私はあなたのことを理解していますが、NHibernateにはまだ新しいので、私はすぐに設計した方法でマップすることはできません。 – scottm

+0

確認してください。したがって、実際のセッションの管理方法をテストする必要があります。それはあなたのテストのような操作ごとのセッションですか?それが事実ならば、それは怠け者ではない(私は個人的に非常にまれに何かを怠惰にしない)。 – Surya

+0

私の問題は私が追ったチュートリアルだと思う。今、NHibernateの理解を少し深めました。リポジトリを変更する必要があります。 – scottm

関連する問題