2010-11-19 1 views
1

NHibernate 프로젝트에서 작업 중이고 transient 엔티티 업데이트에 관한 질문이 있습니다. 다음과 같이NHibernate - 특정 속성을 'dirty'로 플래그 지정

기본적으로 워크 플로는 다음과 같습니다

  1. 는 DTO (돌출부)를 생성하고 클라이언트에 와이어를 보내. 이것은 엔티티의 작은 속성 집합입니다.
  2. 클라이언트가 변경된 DTO를 다시 보냅니다.
  3. DTO 속성을 해당 엔티티에 매핑하면 NH에서 UPDATE 문을 생성하고 실행할 수 있습니다. 나는 문제가 어디
  4. 저장 엔티티

포인트 4입니다. 현재 session.Merge() 메서드를 사용하여이 업데이트를 수행 할 수 있지만 업데이트하기 전에 db (엔트리 없음 2LC)에서 엔티티를 먼저로드해야합니다. 따라서 select 및 update 문이 모두 실행됩니다.

내가 원하는 것은 엔터티의 일시적인 인스턴스를 만들고, DTO에서 새 값을 매핑 한 다음 NH이 내가 변경 한 속성 만 사용하여 SQL 문을 생성하도록하는 것입니다. 엔티티 ID와 SET 절에 필요한 값이 이미 있으므로 추가 선택은 불필요합니다. NH에서 가능합니까?

현재 session.Update()를 사용하면 모든 속성이 업데이트 문에 포함되며 DTO의 일부가 아닌 초기화되지 않은 속성으로 인해 예외가 발생합니다.

본질적으로 어떤 엔티티 속성이 더티인지 지정하는 방법이 필요합니다. 따라서이 속성 만 업데이트에 포함됩니다.

== 편집 == 예

...

public class Person 
{ 
    public virtual int PersonId { get; set; } 
    public virtual string Firstname { get; set; } 
    public virtual string Nickname { get; set; }  
    public virtual string Surname { get; set; } 
    public virtual DateTime BirthDate { get; set; }  
} 

시험 케이스.

// Create the transient entity 
Person p = new Person() 
p.id = 1; 

using (ISession session = factory.OpenSession()) 
{ 
    session.Update(p); 

    // Update the entity – now attached to session  
    p.Firstname = “Bob”; 

    session.Flush(); 
} 

나는 'UPDATE 사람 SET FIRSTNAME ='밥 'WHERE PersonID = 1'과 같은 SQL 문을 생성하는 기대했다. 대신 BirthDate가 초기화되지 않아서 DateTime이 범위를 벗어났습니다. SQL 문에는 필요하지 않으므로 BirthDate가 필요하지 않습니다. 어쩌면 이것은 가능하지 않을까요? 사전에

==/EDIT ==

감사합니다, 존

답변

4

동적 업데이트는 당신이 찾고있는 것입니다. 매핑 파일 (hbm.xml) :

<class name="Foo" dynamic-update="true"> 
    <!-- remainder of your class map --> 

이 경우 발생할 수있는 잠재적 인 문제점에 유의하십시오. 이름이나 닉네임이 null이 아니어야한다고 말하는 도메인 논리가 있다고 가정 해 보겠습니다. (완전하게 이것을 만듭니다.) 두 사람이 Jon "Jonboy"Jonson을 동시에 업데이트합니다. 하나는 그의 FirstName을 제거합니다. 동적 업데이트가 true이기 때문에 update 문은 Jon을 null로 만들고 레코드는 이제 "Jonboy"Jonson입니다. 다른 동시 업데이트는 닉네임을 제거합니다. 그 의도는 Jon Jonboy입니다. 그러나 닉네임의 null-out 만 데이터베이스로 보내집니다. FirstName 또는 Nickname이없는 레코드가 생겼습니다.dynamic-update가 false 인 경우 두 번째 업데이트로 Jon Jonboy가 설정됩니다. 어쩌면 이것은 당신의 상황에서는 문제가 아니지만 dynamic-update = "true"로 설정하면 결과에 영향을 미칠 수 있으므로 그 의미를 생각해 봐야합니다.

업데이트 : 코드를 보내 주셔서 감사합니다. 도움이되었습니다. 기본적인 문제는 NHibernate가 충분한 정보를 가지고 있지 않다는 것이다. 당신이 session.Update (p)를 말할 때, NHibernate는 연결이 끊긴 엔티티를 현재 세션과 연관시켜야한다. 기본이 아닌 PK가 있습니다. 그래서 NHibernate는 그것이 삽입물이 아니라 업데이트라는 것을 압니다. 당신이 session.Update (p)를 말할 때, NHibernate는 전체 엔티티를 더티 (dirty)로보고 그것을 데이터베이스로 보낸다. (당신이 session.Merge (obj)를 사용한다면, NHibernate는 데이터베이스로부터 엔티티를 선택하고 obj를 병합합니다.) 이것은 당신이 정말로 의미하는 것이 아닙니다. 개체를 현재 세션과 연결하고 깨끗하게 표시하려고합니다. API는 다소 비 직관적입니다. 아래와 같이 session.Lock (obj, LockMode.None)을 사용합니다.

using(var session = sessionFactory.OpenSession()) 
using(var tx = session.BeginTransaction()) { 
    var p = new Person {PersonId = 1}; 
    session.Lock(p, LockMode.None); // <-- This is the secret sauce! 
    p.Firstname = "Bob"; 
    // No need to call session.Update(p) since p is already associated with the session. 
    tx.Commit(); 
} 

(NB 동적 업데이트 = "사실은"내 매핑에 지정되어 있습니다.) 이것은 다음과 같은 SQL 결과

:

UPDATE Person 
SET Firstname = 'Bob' /* @p0_0 */ 
WHERE PersonId = 1 /* @p1_0 */ 
+0

뿐만 아니라이를 이용의 성능에 영향이있다 , 정적 업데이 트를 사용하여 (전체) nhibernate가 sessionfactory가 만들어 질 때 업데이 트 문을 준비하는 방법으로 인해 더 performant 믿습니다. – DanP

+0

안녕하세요 제임스, 응답 해 주셔서 감사합니다. 엔티티에 대해 DynamicUpdate (유동적 인 매핑)가 설정되어 있습니다. 어쩌면 예가 문제를보다 명확하게 설명해줍니다. 위의 편집 된 섹션을 참조하십시오. – John

+0

이 경우에는 API가 직관적이지 않음에 동의해야합니다.) '실제'앱에서 session.Lock()을 사용하여 테스트했으며 원하는 SQL을 정확히 반환합니다. 이 James에 대한 당신의 도움에 대해 대단히 감사합니다. – John