1

NHibernateとC#を使用すると、属性の遅延読み込みで読み込まれたオブジェクトの削除で問題が発生します。

オブジェクトはです。

public class Item
{
    public virtual Guid ItemID { get; set; }    
    public virtual string Name { get; set; }
    public virtual decimal Price { get; set; }
    public virtual string Image { get; set; }
    public virtual Iesi.Collections.Generic.ISet<Tax> Taxes { get; set; }
}

「Taxes」コレクションは、遅延読み込みで読み込まれます。だから私はセッションを開いたままにしておく必要があります(私が学んだように)。「Item」オブジェクトをロードするとき、私は次のクエリを使用します。

    public Item FindByID(Guid itemID)
    {
        //using(var session = NHibernateHelper.OpenSession())
        //using (var tr = session.BeginTransaction())
        //{
        //    return session.Get<Item>(itemID);
        //}

        var session = NHibernateHelper.OpenSession();
        return session.Get<Item>(itemID);
    }

上記のコードでFindByID()は、オブジェクトがDBからフェッチされると、セッションを閉じるコードをコメントアウトしていることがわかります。Taxesそれは、オブジェクトコレクションに怠惰にアクセスする必要があるため、セッションを開く必要があるためです。開いているコードセクションには、見つかったオブジェクトを返した後もセッションが開いていることが示されています。

上記のロードされたオブジェクトで次のコードを使用して削除を実行すると、いいえ。

    public void RemoveItem(Item item)
    {            
        using(var session = NHibernateHelper.OpenSession())
        using (var tr = session.BeginTransaction())
        {
            try
            {
                session.Delete(item);
                tr.Commit();
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }
    }

次のエラーが発生します。

コレクションを2つの開いているセッションに関連付けようとする違法な試み

エラーは明らかです。フェッチされたオブジェクトはセッションを開きました。同じオブジェクトを削除するために別のセッションを開くと、このエラーが発生します。

誰かがこのエラーを取り除くために私を案内してください。ありがとう。

4

3 に答える 3

3

エラーは設計にあります。オブジェクトを取得するためにセッションを開いて、開いたままにしています。その後、別のセッションを開いて管理対象オブジェクトを削除しようとしていますが、このセッションを自動的に閉じるつもりです。では、なぜFindByIDメソッドでセッションを閉じないのですか?

上記は矛盾しているため、設計について考える必要があります。または、Morten が言うように、より詳細な質問 (つまり、これをどのように設計する必要があるか) を提示してください。

遅延インスタンスにアクセスする必要があるため、Morten のアプローチを使用し、Web 要求ごとにセッションを使用するか、セッションを含む独自の要求コンテキストを設定することをお勧めします (Web アプリケーションを作成していない場合)。コンテキスト ベースの設計をまだ行っていない場合の簡単な方法は、イベントの開始時にセッションを作成し (つまり、ユーザーがアイテムを削除したい場合)、そのセッションを DAO メソッドに渡すことです。

public Item FindByID(Session session, Guid itemID)
{
    using (var tr = session.BeginTransaction())
    {
        return session.Get<Item>(itemID);
    }
}

public void RemoveItem(Session session, Item item)
{
    using (var tr = session.BeginTransaction())
    {
         session.Delete(item);
         tr.Commit();
    }
}

これをさらに一歩進めて、DAO の外でもトランザクションを作成することができます。これはより高速で、トランザクションを最大限に活用できます (つまり、後で汎用 DAO を介して相互に依存するデータベース アクションを実行する要求が発生する可能性があります)。

于 2013-01-02T10:35:28.680 に答える
1

アクティブなセッションが常に 1 つだけであることを確認する必要があります。次の 2 つの一般的な方法があります。

  • 常にリクエストを転送するサービス層を用意します。このサービス層は、セッション処理 (およびトランザクション処理) を担当します。すべてのビジネス ロジックはセッション レイヤーで処理する必要があるため、常にセッションが存在します。必要なものをすべて UI にロードし、それを応答の一部として返す必要があります。nhibernate を使用する単純な要求応答サービス レイヤーについては、たとえばhttp://davybrion.github.com/Agatha/を参照してください。
  • Web リクエストごとにセッションを作成します。これには通常、コントローラー メソッドが呼び出される前にセッション (およびトランザクション) を開き、その後にトランザクションをコミットする必要があります。通常、これは、セッションを必要とするメソッドに設定した属性を使用して処理されます。思いつきで完全な例を挙げることはできませんが、一般的なアプローチの 1 つがNHibernate 3.0 Cookbookで説明されていることは知っています。
于 2013-01-02T10:41:52.230 に答える
0

Web アプリケーションでセッションごとのリクエスト パターンを使用していると仮定すると、最も簡単な解決策はNHibernateHelper.OpenSession、リクエストの現在のセッションを返すようにメソッドを変更することです。これを機能させるために、セッション アクセスをusingブロックにラップすることはできません。代わりに、global.asax でセッションの有効期間を管理します。

リファクタリングしたくない既存のコードがたくさんある場合は、このアプローチを取ります。リファクタリングする時間があれば、依存性注入を使用して ISession をリポジトリ/クエリ オブジェクトに注入する必要があります。

于 2013-01-02T14:28:47.780 に答える