2009-03-23 3 views
27

방금 ​​NHibernate 세션에서 객체를 가져 와서 객체의 속성을 변경하면 NHibernate가 자동으로 객체를 업데이트하지 않고 발견했다. Session.Update(myObj)!NHibernate의 자동 (더티 검사) 업데이트 동작을 해제하는 방법?

이것이 도움이 될 수있는 방법을 알 수 있지만 기본 동작으로는 미친 것처럼 보입니다!

업데이트 : 내가 지금 지속성 무지를 이해하고, 그래서이 문제가 지금 명확하게 선호하는 옵션입니다. 나는 여기에 모호한 질문을 남겨두고 희망을 갖고 다른 모독적인 사용자들을 도울 것입니다.

어떻게 이런 일을 막을 수 있습니까? 이 기본 NHibernate 행동인가요? 아니면 Fluent NHibernate의 AutoPersistenceModel에서 오는 것입니까?

이 문제를 막을 방법이 없다면 어떻게해야합니까? 요점을 놓치지 않는 한이 행동은 올바른 혼란을 야기하는 것 같습니다. 바로 his answer이 사람은

내가 NHibernate에 2.0.1.4과 유창함 NHibernate에이 18/3/2009

에서 구축 사용하고 있습니까?

나는 Event Listener를 재정의하면이 문제를 해결할 수 있음을 읽었습니다. 그러나이 상황에서는 IDirtyCheckEventListener.OnDirtyCheck이 호출되지 않습니다. 누구 내가 재정의해야 할 청취자를 알고 있습니까?

답변

13

Session.FlushModeFlushMode.Never으로 설정할 수 있습니다. 이렇게하면 조작이 명시 적으로 이루어집니다.

예 : tx.Commit() 또는 session.Flush()입니다. 물론 이것은 커밋/플러시시 데이터베이스를 업데이트합니다. 이 동작을 원하지 않으면 session.Evict(yourObj)을 호출하면 일시적이되고 NHibernate는 db 명령을 실행하지 않습니다.

편집에 대한 응답 : 예, 그 사람은 제어하는 ​​방법에 대한 추가 옵션을 제공합니다.

+1

네,하지만 플러시 할 때 여전히 일어날 것입니다. –

+0

아하, 그런 다음 Session.Evict()를 수행하여 객체를 일시적으로 만드십시오. –

+0

나는 nhibernate가 수동으로 업데이트를 제어하고 싶지 않다는 느낌을받습니다. 이러한 모든 솔루션은 해킹처럼 보입니다. 왜 이런거야? –

1

SaveOrUpdate() 또는 Save()를 호출하면 개체가 영구적으로 유지됩니다. 만약 당신이 Session이나 Persistent Object에 대한 레퍼런스를 사용하여 그것을 가져왔다면, 그 객체는 영속적이며 Session을 flush하면 변경 사항을 저장할 것입니다. 이 동작을 일시적으로 만드는 개체에 대해 Evict()를 호출하면이 동작을 방지 할 수 있습니다.

편집자 추가 : 나는 일반적으로 ISession을 작업 단위로 간주합니다. 이것은 웹 응용 프로그램에서 쉽게 구현됩니다. 세션 당 요청을 사용하지만 WinForms에서 더 많은 제어가 필요합니다.

+0

I Evict 후에 수동으로 개체에 대한 업데이트를 수행 할 수 있습니까? 이 모든 접근 방식이 좋은 아이디어입니까? 모든 개체에 대해이 기본 동작을 수행 할 수있는 방법이 있습니까? 아니면 각 개체를 제거해야합니까? –

+0

퇴거 후에는 개체가 일시적입니다. 다시 저장하려면 SaveOrUpdate를 호출 할 수 있습니다. –

+0

나는 당신이 세션을 일의 단위로 삼으려고한다고 생각한다. 다시 붙일 수있는 방법이 있지만 세션 수명주기를 늘리는 것이 좋습니다. 웹 응용 프로그램에서 이것은 요청 당, 스마트 클라이언트에서는 단위 작업 단위가됩니다. –

3

내 솔루션 : (어딘가에 사출 프레임 워크 등록 내부) 초기 ISession 만들기에

  1. true로 DefaultReadOnly 설정합니다.
  2. NHibernate를 랩핑하고 ISession.Save, Update, SaveUpdate 등을 호출하는 Insert, Update, InsertUpdate 및 Delete (또는 이와 유사한) 메서드에서 ISession 등을 관리하는 IRepository 구현에서 엔티티에 대해 SetReadOnly를 호출하십시오 플래그는 false로 설정됩니다.
+0

감사합니다. –

0

NH와 이벤트 리스너를 사용하여이 작업을 수행했습니다 (이것은 내 작업이 아니지만 내가 수행 한 곳의 링크를 찾을 수 없습니다 ...).우리는 수동에 Save()를 호출 할 때 개체가 지속됩니다 그래서 것으로, 같은로드를 설정 한 다음 저장 (그리고 될 saveOrUpdate)에 대한 일을하고 -

우리는 읽기 전용으로 설정하려면 데이터를 읽을 때의의 EventListener가 .

그 - 또는 상태/ChangeTracking이없는 IStatelessSession을 사용할 수 있습니다.

이 옵션은 엔티티/항목을로드시 즉시 ReadOnly로 설정합니다.

삽입 이벤트 수신기는 하나만 포함되어 있지만 설정 코드는 모두 참조합니다.

/// <summary> 
/// A listener that once an object is loaded will change it's status to ReadOnly so that 
/// it will not be automatically saved by NH 
/// </summary> 
/// <remarks> 
/// For this object to then be saved, the SaveUpdateEventListener is to be used. 
/// </remarks> 
public class PostLoadEventListener : IPostLoadEventListener 
{ 
    public void OnPostLoad(PostLoadEvent @event) 
    { 
     EntityEntry entry = @event.Session.PersistenceContext.GetEntry(@event.Entity); 

     entry.BackSetStatus(Status.ReadOnly); 
    } 
} 

개체를 저장, 우리는

public class SaveUpdateEventListener : ISaveOrUpdateEventListener 
{ 
    public static readonly CascadingAction ResetReadOnly = new ResetReadOnlyCascadeAction(); 

    /// <summary> 
    /// Changes the status of any loaded item to ReadOnly. 
    /// </summary> 
    /// <remarks> 
    /// Changes the status of all loaded entities, so that NH will no longer TrackChanges on them. 
    /// </remarks> 
    public void OnSaveOrUpdate(SaveOrUpdateEvent @event) 
    { 
     var session = @event.Session; 
     EntityEntry entry = session.PersistenceContext.GetEntry(@event.Entity); 

     if (entry != null && entry.Persister.IsMutable && entry.Status == Status.ReadOnly) 
     { 
      entry.BackSetStatus(Status.Loaded); 
      CascadeOnUpdate(@event, entry.Persister, @event.Entry); 
     } 
    } 

    private static void CascadeOnUpdate(SaveOrUpdateEvent @event, IEntityPersister entityPersister, 
     object entityEntry) 
    { 
     IEventSource source = @event.Session; 
     source.PersistenceContext.IncrementCascadeLevel(); 
     try 
     { 
      new Cascade(ResetReadOnly, CascadePoint.BeforeFlush, source).CascadeOn(entityPersister, entityEntry); 
     } 
     finally 
     { 
      source.PersistenceContext.DecrementCascadeLevel(); 
     } 
    } 
} 

(지금 지속됩니다 의미)로드에 해당 객체를 설정하려면이 전화 그리고 우리는 이렇게 너무 NH로 구현 :

public static ISessionFactory CreateSessionFactory(IPersistenceConfigurer dbConfig, Action<MappingConfiguration> mappingConfig, bool enabledChangeTracking,bool enabledAuditing, int queryTimeout) 
    { 
     return Fluently.Configure() 
      .Database(dbConfig) 
      .Mappings(mappingConfig) 
      .Mappings(x => x.FluentMappings.AddFromAssemblyOf<__AuditEntity>()) 
      .ExposeConfiguration(x => Configure(x, enabledChangeTracking, enabledAuditing,queryTimeout)) 
      .BuildSessionFactory(); 
    } 

    /// <summary> 
    /// Configures the specified config. 
    /// </summary> 
    /// <param name="config">The config.</param> 
    /// <param name="enableChangeTracking">if set to <c>true</c> [enable change tracking].</param> 
    /// <param name="queryTimeOut">The query time out in minutes.</param> 
    private static void Configure(NHibernate.Cfg.Configuration config, bool enableChangeTracking, bool enableAuditing, int queryTimeOut) 
    { 
     config.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "none"); 
     if (queryTimeOut > 0) 
     { 
      config.SetProperty("command_timeout", (TimeSpan.FromMinutes(queryTimeOut).TotalSeconds).ToString()); 
     } 

     if (!enableChangeTracking) 
     { 
      config.AppendListeners(NHibernate.Event.ListenerType.PostLoad, new[] { new Enact.Core.DB.NHib.Listeners.PostLoadEventListener() }); 
      config.AppendListeners(NHibernate.Event.ListenerType.SaveUpdate, new[] { new Enact.Core.DB.NHib.Listeners.SaveUpdateEventListener() }); 
      config.AppendListeners(NHibernate.Event.ListenerType.PostUpdate, new[] { new Enact.Core.DB.NHib.Listeners.PostUpdateEventListener() }); 
      config.AppendListeners(NHibernate.Event.ListenerType.PostInsert, new[] { new Enact.Core.DB.NHib.Listeners.PostInsertEventListener() }); 
     } 
    } 
+0

왜 이런 결정을 내릴 수 있습니까? 성능면에서 약간의 이득이 있습니까? – yeska

+0

데이터 모델을 업데이트하는 데 시간이 많이 걸렸지 만 저장하고 싶지 않은지 확실하지 않았습니다 (2 년 전이었습니다). 아치가 아프다는 것은 아마도 저장하려는 내용 만 변경해야하기 때문입니다. 추적 *을 해제하면 이론적으로 성능이 향상됩니다.하지만 수동으로 모든 것을 저장해야합니다. –

관련 문제