1

私のASP.NETMVC4プロジェクトは、AutoTxとNHibernateファシリティを使用して、NHibernate(リポジトリの背後)とCastleWindsorを使用しています。私はhafによって書かれたガイドに従い、オブジェクトを作成して読み取ることができます。

私の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ファシリティクイックスタートから直接取得されます。

ベースリポジトリで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では3つのセッションが表示されます(1つはリポジトリからのGetPrescriber呼び出し用、1つは更新用(SQLなし)、もう1つは基本クラスのactionfilterのアクション用)。また、暗黙のトランザクションの使用に関するアラートを受け取ります。AutoTxとTransaction属性を使用して、トランザクションを取得するために必要なすべてのことを実行していると思ったため、これは混乱を招きます。また、Windsorの構成に従って、Webリクエストごとに1つのセッションしかないことも期待していました。

更新:自動トランザクション用のNHibernateFacilityとAutoTxファシリティのソースを読んで一日を過ごした後、AutoTxはINHibernateInstallerの実装にインターセプターを設定していないようです。これは、SessionManagerがOpenSessionを呼び出すときは常に、インターセプターを受け入れるバージョンではなく、パラメーターなしのデフォルトバージョンを呼び出していることを意味しているようです。AutoTxFacilityはTransactionInterceptorをwindsorに内部的に登録するため、WindsorはAutoTxのTransactionalComponentInspectorを利用して、INHibernateInstallerコンクリートにInterceptorを追加できます。

githubのAutoTxFacilityソース

4

3 に答える 3

2

私には、リポジトリへの呼び出しごとにセッションを作成しているように見えます。セッションは、事業運営全体に及ぶ必要があります。最初に開いて、最後にコミットして破棄する必要があります。

このコードには他にも奇妙なことがあります。

  • コミットは、SaveOrUpdateとはまったく異なる概念です。
  • そして、とにかく変更を保存するようにNHに指示する必要はありません。session.Saveを呼び出す必要はありません。すでにセッションにあるオブジェクトを保存します。とにかく保存されます。セッションを呼び出すだけで済みます。新しいオブジェクトを追加するときに保存します。
  • 事業運営全体でトランザクションを使用するようにしてください。
于 2012-12-04T06:38:10.193 に答える
1

上記のコードスニペットには、最も可能性の高い「意図しない」部分が1つあります。そしてNHProfによる観察によって証明された

ああ、NHProfでは3つのセッションが表示されます(1つはリポジトリからのGetPrescriber呼び出し用、1つは更新用(SQLなし)、もう1つは基本クラスのactionfilterのアクション用)。

を呼び出すと、新しいセッションインスタンスOpenSession()の作成がトリガーされます。

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

したがって、コードがSessionプロパティにアクセスしているときはいつでも、背後に新しいセッションインスタンスが作成されます(何度も繰り返します)。get用に1つのセッション、udpate用に1つ、filter用に1つ...

ここでわかるように、によって返されるセッションは、SessionManager.OpenSession()スコープ全体(作業単位、Web要求...)で使用する必要があります。

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

必要な構文は、1つのセッションを作成し(最初にアクセスしたとき)、スコープのenfまで再利用します(その後、正しく閉じ、トランザクションをコミットまたはロールバックします...)。とにかく、今のところ最初に行うことは、Sessionこのようにプロパティを変更することです。

ISession _session;
protected ISession Session
{
    get 
    { 
      if (_session == null)
      {
         _session = sessionFactory.OpenSession();
      }
      return _session; 
    }
}
于 2012-12-04T07:19:22.123 に答える
0

昨日、githubのAutoTxとNHibernateの機能を検索してどこにも行かなくなった後、問題を再現するためにクリーンなプロジェクトを開始しました。残念ながら、レプリケーションではすべてが機能しました。ソースでUpdate-Packageを実行し、Castle.Transactionsの新しいバージョンを停止しましたが、正しく実行されていました。私は自分のコードに小さな調整を加えました。これは、UserRepository.Commit行を削除することでした。

セッションを開く方法を変更する必要はありませんでした。これは、SessionManagerインスタンスによって処理されました。Castle.Transactionsの更新により、Transaction属性が認識され、トランザクションが作成されます(NHProfでアラートがなくなったことからもわかります)。

于 2012-12-05T22:04:25.350 に答える