2009-08-20 34 views
1

我有一個類,任務,它有一個屬性TaskLibrary這是它會加載和運行一些代碼。所以,任何任務都有一個庫,但是任何庫都可以有很多任務。我的問題是,我的測試確保任務的庫屬性不爲null是失敗的(所以它可能只是我的測試)。我的類是有效的:幫助我測試與NHibernate和NUnit的一對多的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的映射是這樣的:

<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> 

我的測試類是這樣的:

[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); 
    } 
    } 

而且,任務表中MSSQL2000數據庫是這樣的:

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

如果你還在我身邊...

從我的Task類中,我只想爲Library屬性的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建議和其他一些),將不勝感激。

編輯:

變化取=「加入」後,我發現了我從Task類想要的功能。不過,我添加了另一個測試爲TaskLibrary類的任務屬性:

[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"); 
    } 

但是,斷言失敗,此錯誤(我已經更新上面的代碼,以反映我所做的更改):

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

這是因爲您只能在會話打開時進行延遲加載。你不會急於加載TaskLibrary.Tasks,因爲這可能會以遞歸的方式發出大量的select語句。 – dotjoe 2009-08-20 16:49:35

+0

@dotjoe,對。這就是爲什麼我設置了lazy =「true」,但它仍然拋出異常。所以,我不知道延遲加載是如何工作的。 – scottm 2009-08-20 16:55:09

+0

基本上,延遲加載通過擴展您的poco(使用虛擬屬性)並在您嘗試使用它加載的會話時訪問其中一個屬性。如果會話關閉,您會收到錯誤消息。因此,在您嘗試訪問任務之前,會話已打開並關閉。 – dotjoe 2009-08-20 17:02:53

回答

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 2009-08-20 16:23:38

+0

是的,您也可以在多對一的情況下簡單地設置lazy =「false」,它將立即發出單獨的select語句。當你設置fetch =「join」時,我認爲懶惰屬性沒有意義......但我並不是100%。 – dotjoe 2009-08-20 16:28:28

+0

我明白了。謝謝! – scottm 2009-08-20 16:37:43

0
+0

還要檢查你正在處理的工作單元......如果每個訪問被包裝在它自己的事務中,你可能會得到No Session錯誤。看到這個例子:http://stackoverflow.com/questions/345705/hibernate-lazyinitializationexception-could-not-initialize-proxy – 2009-08-20 16:03:24

+0

我剛剛做了,但我得到了同樣的例外。雖然,我確實需要從TaskLibrary類延遲加載任務。 – scottm 2009-08-20 16:03:34

0

不要更改測試的映射,你的要求應該驅動對象的映射。 您的存儲庫方法在從數據庫獲取數據後關閉會話。您需要保持整個測試方法的會話打開。 要弄清楚如何做到這一點,你需要告訴我們你是如何管理你的會話。那些綁定到一個事務/ threadlocal?

+0

這不是我理解它的方式。應該首先創建測試來驅動代碼創建(即第一次測試應該失敗)。我理解你的觀點,但我仍然對NHibernate不熟悉,所以我不能按照我設計的方式進行映射。 – scottm 2009-08-20 16:50:15

+0

確定。所以你的測試應該反映會議如何在真實情況下進行管理。每次操作都像在你的測試中一樣嗎?如果是這樣的話肯定會繼續做它不懶惰(我個人很少做任何不懶惰) – Surya 2009-08-20 17:16:20

+0

我認爲我的問題是我跟着的教程。現在我對NHibernate有了更好的理解,我將不得不修改我的存儲庫。 – scottm 2009-08-20 17:24:16