2012-12-04 140 views
1

我的ASP.NET MVC 4項目使用NHibernate(位於倉庫後面)和Castle Windsor,使用AutoTx和NHibernate Facilities。我遵循haf編寫的指南,我可以創建和讀取對象。NHibernate不堅持更改我的對象

我PersistenceInstaller看起來像這樣

public class PersistenceInstaller : IWindsorInstaller 
{ 
    public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store) 
    { 
     container.AddFacility<AutoTxFacility>();    
     container.Register(Component.For<INHibernateInstaller>().ImplementedBy<NHibernateInstaller>().LifeStyle.Singleton); 
     container.AddFacility<NHibernateFacility>(
      f => f.DefaultLifeStyle = DefaultSessionLifeStyleOption.SessionPerWebRequest);   
    } 
} 

的NHibernateInstaller是直接從NHib Facility Quickstart

我在我的基地倉庫使用ISessionManager ...

protected ISession Session 
{ 
    get 
    { 
     return _sessionManager.OpenSession(); 
    } 
} 

public virtual T Commit(T entity) 
{ 
    Session.SaveOrUpdate(entity);    
    return entity; 
} 

最後,這是造成這個問題我的應用程序代碼:測試

[HttpPost] 
[ValidateAntiForgeryToken]   
[Transaction] 
public ActionResult Maintain(PrescriberMaintainViewModel viewModel) 
{   
    if (ModelState.IsValid) 
    { 
     var prescriber = UserRepository.GetPrescriber(User.Identity.Name); 

     //var prescriber = new Prescriber { DateJoined = DateTime.Today, Username = "Test" };     
     prescriber.SecurityQuestion = viewModel.SecurityQuestion; 
     prescriber.SecurityAnswer = viewModel.SecurityAnswer; 
     prescriber.EmailAddress = viewModel.Email; 
     prescriber.FirstName = viewModel.FirstName; 
     prescriber.LastName = viewModel.LastName; 
     prescriber.Address = new Address 
           { 
            Address1 = viewModel.AddressLine1, 
            Address2 = viewModel.AddressLine2, 
            Address3 = viewModel.AddressLine3, 
            Suburb = viewModel.Suburb, 
            State = viewModel.State, 
            Postcode = viewModel.Postcode, 
            Country = string.Empty 
           }; 

     prescriber.MobileNumber = viewModel.MobileNumber; 
     prescriber.PhoneNumber = viewModel.PhoneNumber; 
     prescriber.DateOfBirth = viewModel.DateOfBirth; 
     prescriber.AHPRANumber = viewModel.AhpraNumber; 
     prescriber.ClinicName = viewModel.ClinicName; 
     prescriber.ClinicWebUrl = viewModel.ClinicWebUrl; 
     prescriber.Qualifications = viewModel.Qualifications; 
     prescriber.JobTitle = viewModel.JobTitle; 


     UserRepository.Commit(prescriber);   
    } 

    return View(viewModel); 
} 

上面的代碼將保存一個新的處方(通過取消註釋掉的註釋等)。

我正在使用NHProf並已確認沒有將sql發送到數據庫以進行更新。我可以看到正在執行的讀取,但就是這樣。

在我看來,NHibernate不承認實體被更改,因此不會生成SQL。或者可能交易沒有被提交?

我一直在網上衝刷了幾個小時,現在試圖完成這一個,並作爲絕望的最後一幕在SO上發佈。有任何想法嗎? :)

哦,在NHProf中,我看到三個會話(1爲來自回購的GetPrescriber調用,我假設用於更新(沒有sql) - 一個用於我在基類的actionfilter中的某個動作)。我也收到關於使用隱式事務的警報。這讓我感到困惑,因爲我認爲我正在做我需要的所有事情 - 使用AutoTx和Transaction屬性。根據我的Windsor配置,我也預計每個webrequest只有一個會話。

更新:看來,花費了閱讀NHibernateFacility和AutoTx Facility的源代碼進行自動事務處理的一天之後,AutoTx沒有在我的INHibernateInstaller實現上設置攔截器。這似乎意味着每當SessionManager調用OpenSession時,它都會調用不帶參數的默認版本,而不是接受Interceptor的版本。內部AutoTxFacility註冊TransactionInterceptor與溫莎,以便它可以添加攔截我INHibernateInstaller混凝土,由溫莎利用的AutoTx的TransactionalComponentInspector的

AutoTxFacility source on github

+0

是否有錯誤信息?或者只是沒有改變持續? –

+0

沒有錯誤消息。只是沒有數據庫的SQL。我假設我做錯了什麼,我只是不知道我做錯了什麼 –

回答

0

花費了整整一天昨日通過GitHub上還是一無所獲的AutoTx和NHibernate設施搜索後,我在試圖啓動一個乾淨的項目複製問題。不幸的是,複製,一切工作!我在我的源代碼上運行Update-Package並取消了新版本的Castle.Transactions,並且我正確運行。我對自己的代碼做了一些小調整。那是刪除UserRepository.Commit行。

我不需要修改我打開會話的方式。這由SessionManager實例處理。隨着Castle.Transactions的更新,Transaction屬性被識別並且正在創建一個事務(NHProf中沒有更多的警報就證明了這一點)。

2

對我來說,它看起來像每次調用庫創建會話。會議應該涵蓋整個業務運作。它應該在開始時打開並在最後進行處理和處置。

這段代碼還有其他奇怪的東西。

  • 提交是一個完全不同於SaveOrUpdate的概念。
  • 而且無論如何您都不需要告訴NH來存儲更改。您不需要爲會話中已有的對象調用session.Save。無論如何都存儲它們。添加新對象時,只需調用session.Save。
  • 確保您使用整個業務操作的交易。
+0

謝謝。我的理解是SessionManager處理了會話的創建,並且如果存在於當前請求中,它將被重新使用。因此,我預計只會看到一個會話。回到Nhibernate Facility wiki入口,我發現它上週更新了一些關鍵信息,當我在一個月前更改爲使用SessionManager時沒有這些信息。我同意Commit命名,但是我正在處理現有的AbstractRepository,它在任何地方都使用Commit動詞。不管Commit有更多的交易語義,最終的結果仍然是一樣的。再次感謝 –

1

在上面的代碼片段中有一個很可能是「無意」的部分。一個用於 一些動作 - 並通過NHProf

哦,在NHProf我看到三個交易日(1個用於GetPrescriber呼叫 從回購,一個我承擔更新(沒有SQL)製成的觀察證明在基礎類的actionfilter中)。

調用會話實例OpenSession()被觸發創作。

protected ISession Session 
{ 
    get { return _sessionManager.OpenSession(); } 
} 

所以,當代碼訪問Session財產,後面是創建(連連)新的會話實例。對於得到的,一個是UDPATE,一個用於過濾的一個會議......

正如我們所看到的,通過SessionManager.OpenSession()返回的會話必須用於整個範圍(工作單位,網頁的請求......)

http://docs.castleproject.org/Windsor.NHibernate-Facility.ashx

這是我們需要的,SI創建一個會話(時首先訪問),並重新使用它,直到範圍ENF的syntaxh(後來正確地將其關閉,提交或回滾事務...)。總之,第一件事情,現在就是這樣改變Session屬性:

ISession _session; 
protected ISession Session 
{ 
    get 
    { 
     if (_session == null) 
     { 
     _session = sessionFactory.OpenSession(); 
     } 
     return _session; 
    } 
} 
+0

肯定Radim。正如我在Stefans回答中所評論的那樣,當我添加SessionManager時,NHib Facility wiki沒有這些信息(如歷史視圖所證實的:))。現在我可以在wiki中看到額外的細節我知道我需要添加IsWeb標誌並掛接SessionWebModule - 我剛纔期望的東西被照顧了,因爲wiki中沒有信息 - 而不是使用會話工廠創建會話實例......歡呼聲。 –