2010-03-10 50 views
2

比方說,我有一個Type II SCD數據庫,基本上只是追加。我使用NHibernate將對象保存到我的數據庫。我有這樣一個對象,以便:如何更新一行並在NHibernate中自動插入一個新的行,並保存一個調用?

Pony 
|- int Id 
|- Guid EntityId 
|- string PonyName 
|- string PonyColor 
|- int RevisionValidFrom 
|- int RevisionValidTo 

下面是一個典型場景:

Pony myLittlePony = myStable.GetLatestPonyByGuid("0f1ac08a-3328-43db-b278-77c272e4fea3"); 
myLittlePony.PonyColor = "Fish"; 
myNHSession.Save(myLittlePony); 

我希望能夠調用Session.Save(myLittlePony),並有NHibernate的更新舊實體RevisionValidTo到任何我指定,然後將修改爲Pony作爲一個新的行,新的Id,基本上就好像它是一個全新的對象持久化到數據庫。

回答

0

我最終創建了自己的SaveOrUpdateEventListener並在NHibernate的配置中註冊它。然後我發出一個原始的SQL命令。

對於NHibernate的配置:

var listener = new PonySaveOrUpdateEventListener(); 
config.SetListener(NHibernate.Event.ListenerType.SaveUpdate, listener); 
config.SetListener(NHibernate.Event.ListenerType.Save, listener); 

類:

public class PonySaveOrUpdateEventListener : DefaultSaveOrUpdateEventListener 
{ 
    protected override object EntityIsPersistent(SaveOrUpdateEvent @event) 
    { 
     Pony ent = @event.Entity as Pony; 

     // I don't care if it's not a pony or if the entity doesn't need updating, call base! 
     if (ent == null || !IsDirty(@event)) 
      return base.EntityIsPersistent(@event); 

     // Do nasty dialect-specific raw SQL because using NH to update this row throws us into an infinite loop 
     string tablename = ((ILockable)@event.Entry.Persister).RootTableName.ToLower(); 
     System.Data.IDbCommand command = ((ISession)@event.Session).Connection.CreateCommand(); 
     command.CommandText = String.Format("update {0} set RevisionValidTo = {1} where Id = '{2}'", tablename, CurrentRevision.Id, ent.Id); 
     command.ExecuteNonQuery(); 

     // Make the event look like it was never persistent and force a transient insert of the entity 
     ent.Id = Guid.Empty; 
     @event.Entry = null; 
     return EntityIsTransient(@event); 
    } 

    protected override object EntityIsTransient(SaveOrUpdateEvent @event) 
    { 
     Pony ent = @event.Entity as Pony; 
     if (ent == null) 
      return base.EntityIsTransient(@event); 

     ent.RevisionValidFrom = Host.NextRevision; 
     ent.RevisionValidTo = null; 

     return base.EntityIsTransient(@event); 
    } 

    private static bool IsDirty(SaveOrUpdateEvent @event) 
    { 
     IEntityPersister persister = @event.Entry.Persister; 
     object[] oldState = @event.Entry.LoadedState; 
     object[] currentState = persister.GetPropertyValues(@event.Entity, @event.Session.EntityMode); 
     Int32[] dirtyProps = persister.FindDirty(currentState, oldState, @event.Entity, @event.Session); 
     return dirtyProps != null; 
    } 
} 
+0

沒有了ISession.SaveOrUpdate()方法勝任這項工作? – 2010-03-15 20:04:21

+0

@威爾:做什麼工作?你讀過這個問題了嗎? – snicker 2010-03-15 20:09:28

相關問題