1

私のプロジェクトでは、NHibernate と Net Persistence API を C# と MySql db で使用しており、UI レイヤー (ASP.NET)、ビジネス レイヤー、およびデータ アクセス レイヤー (DAL) を使用しています。DAL の UserManager クラスに次の Save メソッドがあります。

        private EntityManager GetEm()
        {
            if (_entityManager == null)
            {
                _entityManagerFactory = Persistence.CreateEntityManagerFactory("JPUMain");
                _entityManager = _entityManagerFactory.CreateEntityManager();
            }
            return _entityManager;
        }

        public void **Save**(IGenericEntity entity)
        {
            _entityManager = GetEm();
            _entityManager.GetTransaction().Begin();
            _entityManager.Persist(entity);
            _entityManager.Flush();            
            _entityManager.GetTransaction().Commit();            
            _entityManager.Clear();
        }

私のユーザー エンティティ:

 [Entity]
 [Table(Name = "user")]
 public class User : IGenericEntity
    {
        [Id]
        [GeneratedValue]
        public virtual int ID { get; set; }

        [Basic]
        [Column(Name = "fname", Nullable = false)]
        public virtual string FirstName { get; set; }

        [Basic]
        [Column(Name = "lname", Nullable = false)]
        public virtual string LastName { get; set; 
    }

今、次のように呼び出してユーザーを保存しようとしている場合:

UserManager.save(user)

次に、エントリをdbに適切に保存します。しかし、次回 (同じセッションではなくいつでも) ユーザーの詳細を変更しようとすると、更新コマンドを起動する代わりに挿入を起動し、変更ユーザー エンティティを使用して新しいレコードを挿入します。ユーザーの主キーを変更されたオブジェクトに正しく設定しています。

また、NUnit を使用して同じテスト ケースを実行すると、次の行が出力されます。

NHibernate: SELECT LAST_INSERT_ID()
NHibernate: INSERT INTO user (uid, fname, lname) VALUES (?p0, ?p1, ?p2);?p0 = 2[Type: Int32 (0)], ?p1 = 'First Name' [Type: String (9)], ?p2 = 'Last Name' [Type: String (9)]

ユーザーテーブルのphpmyadminから直接このステートメントを実行しようとしましたが、常に0の値が返されます。InnoDB エンジンを使用しています。

既存のユーザーエンティティを更新していない理由を教えてください。代わりに、変更されたエンティティで新しいレコードを作成していますか?

4

2 に答える 2

0

エンティティの取得に使用した ISession とは別の ISession にエンティティを保存しています。

あなたができる最善のことは、同じ ISession を使用していることを確認することです。それをどのように管理するかを真剣に考えるべきだと思います。セッションは短時間で終了する必要があるため、さまざまなユース ケースを処理する何らかのサービス レイヤーを作成することをお勧めします。

于 2013-01-06T20:00:12.010 に答える
0

Persist が更新を起動することはありません。

NH ソースを掘り下げると、 DefaultPersistEventListenerに実際に実装されている Persist がエンティティの状態をチェックすることがわかります。

public class DefaultPersistEventListener : AbstractSaveEventListener, IPersistEventListener
{
    //..
    public virtual void OnPersist(PersistEvent @event, IDictionary createdAlready)
    {
        //... 
        EntityState entityState = GetEntityState(entity, @event.EntityName, source.PersistenceContext.GetEntry(entity), source);

        switch (entityState)
        {
            case EntityState.Persistent:
                EntityIsPersistent(@event, createdAlready);
                break;
            case EntityState.Transient:
                EntityIsTransient(@event, createdAlready);
                break;
            case EntityState.Detached:
                throw new PersistentObjectException("detached entity passed to persist: " + GetLoggableName(@event.EntityName, entity));
            default:
                throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
        }

}

メソッド EntityIsTransient のみが挿入を DB に送信します。したがって、更新を行っているセッションのコンテキストでは、問題のエンティティは一時的です。フラッシュする前に、このエンティティをセッションのコンテキストにロードまたはアタッチする必要があります。SaveOrUpdate メソッドは、便利なショートカットになる可能性があります。

于 2013-01-06T20:17:02.863 に答える