2

バージョン フィールドを使用して、ASP.NET MVC 4 アプリケーションで同時実行を制御しています。

マッピング:

      <class name="User" table="Users">
        <id name="Id">
          <generator class="native"/>
        </id>
        <version name="Version" column="Version"/>
... other fields omitted for brevity...

実在物:

    public class User
    {
            public virtual int Id { get; set; }
            public virtual int Version { get; set; }
... other fields omitted for brevity...

私は次のアプローチを使用しています。

  • Id でエンティティを読み取り、UserDto エンティティにマップします (Dto はデータ転送オブジェクト パターン用です)。Version フィールドも含まれます
  • UserDto エンティティを編集するためのフォームを表示する
  • POSTed UserDto エンティティを受け取る

次に、次のことを行います。

        // read the original entity from the database using my repository wrapper around NHibernate
        var rep = RepositoryFactory.Create<User>(currentUnitOfWork);
        User originalEntity = rep.GetById(userDto.Id);

        // optimistic lock control - keep the version as the user saw it
        originalEntity.Version = userDto.Version;
... other fields omitted for brevity...

        rep.Update(originalEntity);

問題は、userDto.Version が originalEntity.Version と一致しない場合でも、NHibernate は私の userDto.Version を無視し、originalEntity.Version を使用することです (明らかに、エンティティが読み取られたばかりなので、最初のレベルのキャッシュから)。このような動作により、私の Version フィールドは完全に役に立たなくなります。

NHibernate に、キャッシュされたバージョンではなく、提供されたバージョンの値を使用させるにはどうすればよいですか?

また、私のリポジトリを使用している他のプログラマーに対してバージョン管理をより透過的にすることは素晴らしいことですが、現在、受信したエンティティからバージョンを自動的に取得し、NHibernate にプログラマーなしでそれを使用させる方法がわかりません。気づいても。

何か案は?

4

3 に答える 3

1

これは古い質問であることは承知していますが、ここでは通常のアプローチを残しておきます。

これは、ORM を使用する場合の既知の「問題」です。NHibernate と Entity Framework の両方がこの「問題」に悩まされており、これは、ORM がプロパティによって返されたものを使用するのではなく、内部でバージョン値を追跡しているために発生します。Array.Copy を使用して byte[] 値をコピーできる EF とは異なります。 、NHibernate では通常、セッションからエンティティを削除してから更新を行います。これは、既存のエンティティを更新していることを NHibernate に示しますが、割り当てたばかりのバージョンを使用して追跡を開始します。

コード スニペットを次に示します。

public void Edit(int id, string description, DateTime version)
{
    using (var session = sessionFactory.OpenSession())
    using (var tx = session.BeginTransaction())
    {
        var record = session.Get<Record>(id);
        record.Version = version;
        record.Description = description;

        session.Evict(record);  //  evict the object from the session
        session.Update(record); //  NHibernate will attach the object, and will use your version

        tx.Commit();
    }
}

モデル クラス ( example ) で通常行うようにインターフェイスを使用すると、拡張メソッドを簡単に作成でき、人々が忘れにくくなります。

私の知る限り、このアプローチで問題は見つかりませんでしたが、何か問題が見つかったらお知らせください。

于 2015-09-29T15:42:33.647 に答える
0

あなたは見ることができます@これ

ただし、インターセプターは古い概念であるため、カスタム イベント リスナーで DefaultUpdateEventListener を拡張し、以下のように OnSaveOrUpdate メソッドをオーバーライドできます。

var source = @event.Session;
var entity = @event.Entity;
var persister = @event.Session.GetEntityPersister(@event.EntityName, entity);
if (persister.IsVersioned)
{
    var mode = source.GetSessionImplementation().EntityMode;
    var id = persister.GetIdentifier(entity, mode);

    var version = persister.GetVersion(entity, mode);
    var currentVersion = persister.GetCurrentVersion(id, source);

    if (!version.Equals(currentVersion))
    {
        throw new StaleObjectStateException(persister.EntityName, id);
    }
}

ここでの唯一の問題は、GetCurrntVersion が DB 呼び出しを送信することです。そのため、すべての通話が課金されるため、クラウド アプリケーションにはあまり適したソリューションではありません。

または、セッションからオブジェクトを削除することもできます。ただし、第 1 レベルのキャッシュの利点は失われます。

より良い解決策が見つかったら、投稿します。

于 2014-02-26T10:47:07.347 に答える