3

初めてfluentnhibernateを使用して、リモートMySqlサーバーにアクセスするための既存のデータベースアクセスレイヤーを段階的に廃止します。

クライアントはほとんど仮想化されており、任意の時点(数秒から数日)でスリープ/休止状態になります。通常はサーバーと時間同期しているため保証できませんがDateTime、一部のフィールドで提供されているクライアントを使用できません。

サーバー時間で特定のフィールドを設定/更新するためにnhibernateを取得するにはどうすればよいですか(できればUTC_TIMESTAMP()関数を呼び出すことによって)?

物体:

public class MyObject{
  public virtual UInt64 Id { get; set; }
  public virtual String Status{ get; set; }
  public virtual String SomeData{ get; set; }

  //Set only once when the Object is inserted
  public virtual DateTime TimeCreated { get; set; }
  //Set every time the object is updated
  public virtual DateTime TimeLastUpdate { get; set; }
  //Set every time the 'Status' column is updated
  public virtual DateTime TimeStatusLastChanged { get; set; }
  //This is a user provides standard datetime field
  public virtual DateTime SomeUserSpecifiedTime { get; set; }
}

マッピング:

Id(x => x.Id)
  .GeneratedBy.Native();
Map(x => x.Status);
Map(x => x.SomeData);
Map(x => x.SomeUserSpecifiedTime);
//? -->
Map(x => x.TimeCreated)
  .Not.Update();
Map(x => x.TimeLastUpdate);
Map(x => x.TimeStatusLastChanged);
//<-- ?

Time*3つのフィールドが設定/更新されたときに関数を使用するようにしたいUTC_TIMESTAMP()ので、サーバー側の日付/時刻が挿入されます。DateTime SomeUserSpecifiedTimeフィールドは、標準のマップされたフィールドです。

これまで、私のデータベースアクセスクラスには、その方法でクエリを作成するためのロジックが含まれていました。マッピングを使用してデータベーストリガーを作成することはできました.Generated.Insert/Alwaysが、それを行うためのnhibernate/コードのみの方法があることを望んでいました。

私が見つけた解決策の1つは、サーバーから時間をフェッチして挿入/更新に提供することですが、フェッチと挿入/更新の間の時間がかなり長くなる可能性があるため、それはありません。

4

2 に答える 2

1

トリガーを使用して問題を解決することにしました。これは最適ではありませんが、現時点では機能します。残念ながら、nhibernateにはトリガーの概念がないため、トリガーを補助データベースオブジェクトとして宣言する必要があります。これにより、いくつかの問題が発生します。

  • SchemaValidatorとSchemaUpdateはauxDbObjectsを取得しないため、それらを更新/作成しません。SchemaExportはそれらを作成しますが、2回作成するため、さらに多くのコードの重複が発生します。
  • トリガーごとにインスタンスを作成して登録する必要があり、面倒です。

こんな感じかもしれません

public class MyTrigger : IAuxiliaryDatabaseObject{

  public string SqlCreateString(Dialect dialect, IMapping p, string defaultCatalog, string defaultSchema){
    //The drop is important, because the shema export calls and executes this twice.
    return @"
DROP TRIGGER IF EXISTS myTrigger;

CREATE TRIGGER myTrigger BEFORE INSERT ON myObjectTable FOR EACH ROW 
BEGIN
set new.TimeAdded = UTC_TIMESTAMP();
END";
    }

    public string SqlDropString(Dialect dialect, string defaultCatalog, string defaultSchema){
    return @"DROP TRIGGER IF EXISTS myTrigger";
    }

  public void AddDialectScope(string dialectName){
    throw new NotImplementedException();
    }

  public bool AppliesToDialect(Dialect dialect){
    return true;
    }

  public void SetParameterValues(IDictionary<string, string> parameters){
    throw new NotImplementedException();
    }
  }

構成では、各トリガー/補助。データベースオブジェクトは個別に追加する必要があります。

Fluently.Configure()
  .Database(...)
  .ExposeConfiguration(conf =>
    {
    conf.AddAuxiliaryDatabaseObject(new MyTrigger());
    });

マッピング

Map(x => x.TimeCreated)
  .Not.Update()
  .CustomType("UtcDateTime")
  .ReadOnly()
  .Generated.Insert()   //.Generated.Always() for columns that track lastModification
  ;

カスタムユーザータイプまたはインターセプターは残念ながら機能しないため、現時点でこれを実現する唯一の方法のようです。

于 2012-09-18T13:26:06.210 に答える
0

これはトリックを行う必要があります

Map(x => x.TimeStatusLastChanged)
             .Not.Nullable()
             .Default("UTC_TIMESTAMP()");
于 2012-09-11T20:36:03.950 に答える