2013-01-02 3 views
1

NHibernate 및 C#을 사용하여 특성 지연로드로로드 된 개체를 삭제하는 데 문제가 있습니다.세션 및 지연로드 작업

개체입니다.

public class Item 
{ 
    public virtual Guid ItemID { get; set; }  
    public virtual string Name { get; set; } 
    public virtual decimal Price { get; set; } 
    public virtual string Image { get; set; } 
    public virtual Iesi.Collections.Generic.ISet<Tax> Taxes { get; set; } 
} 

"세금"컬렉션은 여기에서 느린 로딩과 함께로드됩니다. 그래서 저는 세션을 계속 열어 둘 필요가 있습니다. "Item"개체를로드 할 때 다음 쿼리를 사용합니다. FindByID()에 대한 위의 코드에서

public Item FindByID(Guid itemID) 
    { 
     //using(var session = NHibernateHelper.OpenSession()) 
     //using (var tr = session.BeginTransaction()) 
     //{ 
     // return session.Get<Item>(itemID); 
     //} 

     var session = NHibernateHelper.OpenSession(); 
     return session.Get<Item>(itemID); 
    } 

는 내가 객체가 DB에서 가져온되면 세션을 닫는 몇 가지 코드를 댓글을 달았 볼 수 있습니다. 왜냐하면 나는 Taxes 객체 컬렉션을 게으른 액세스 할 수 있으므로 세션을 열어야하기 때문입니다. 공개 코드 섹션은 발견 된 객체를 반환 한 후에 세션이 아직 열려 있음을 나타냅니다.

아니요 위의로드 된 개체와 함께 다음 코드를 사용하여 삭제를 실행할 때 아니오. 나는 다음과 같은 오류를 얻고있다

public void RemoveItem(Item item) 
    {    
     using(var session = NHibernateHelper.OpenSession()) 
     using (var tr = session.BeginTransaction()) 
     { 
      try 
      { 
       session.Delete(item); 
       tr.Commit(); 
      } 
      catch (Exception Ex) 
      { 
       throw Ex; 
      } 
     } 
    } 

은 ..

이 개 열린 세션

오류가 분명하다로 컬렉션을 연결할

불법 시도, 페치 된 객체는 경우 세션을 열었습니다 같은 개체를 삭제하기 위해 다른 세션을 엽니 다.이 오류가 발생했습니다.

이 오류를 없애기 위해 누군가 안내해주십시오. 감사.

+0

아마도 질문이 무엇인지 지정해야합니다. 오류라고 분명히 말하면됩니다 (직접 말한 것처럼). –

+0

내 질문은 ..이 오류를 해결하는 방법? 나는 그 질문에 따라 그것을 썼다. 하지만 지금은 그것을 볼 수 없습니다. 운영자가 삭제할 수 있습니까 ??? – BlueBird

+2

위의'RemoveItem' 메쏘드가 실제 코드라면'catch (Exception ex) throw Ex;'하지 말고 스택 트레이스를 풀 것입니다 - 대신'catch (Exception ex) throw;'를 실행하십시오. 또한, 만약 당신이 할 일을 모두 던지면 예외를 잡아 내지 말고, 아마도'tr.Rollback()'또는 무엇인가를해야 할 것이다. –

답변

3

오류는 사용자의 디자인입니다. 개체를 가져 와서 열어 두는 세션을 여는 중입니다. 그런 다음 다른 세션을 열어 관리 객체를 삭제하지만이 세션을 자동으로 닫으려고합니다. 그러면 FindByID 방법으로 세션을 닫지 않는 이유는 무엇입니까?

위와 일치하지 않는 디자인에 대해 생각해 봐야합니다. 또는 Morten이 말했듯이보다 심오한 질문을 던집니다 (즉, 어떻게 설계해야하는지).

게으른 인스턴스에 액세스해야하기 때문에 Morten의 접근 방식을 사용하고 웹 요청 당 세션을 사용하거나 세션이있는 요청 양식 컨텍스트를 설정하는 것이 좋습니다 (예 : 웹 응용 프로그램). 컨텍스트 기반 디자인이 아직없는 경우보다 쉬운 방법은 이벤트 시작 부분 (즉, 사용자가 항목을 삭제하려는 경우)에서 세션을 만들고 세션을 DAO 방법으로 전달하는 것입니다.

public Item FindByID(Session session, Guid itemID) 
{ 
    using (var tr = session.BeginTransaction()) 
    { 
     return session.Get<Item>(itemID); 
    } 
} 

public void RemoveItem(Session session, Item item) 
{ 
    using (var tr = session.BeginTransaction()) 
    { 
     session.Delete(item); 
     tr.Commit(); 
    } 
} 

이 단계를 더 진행하고 DAO 외부에서 트랜잭션을 생성 할 수 있습니다.이 트랜잭션은 트랜잭션을 최대한 활용할 수 있습니다 (나중에 일반 DAO를 통해 서로에 의존하는 데이터베이스 작업을 수행하는 요청을 가질 수 있습니다) .

+0

예 @TonyDay, FindByID 메소드에서 필자는 UI에서 출력하기 위해 게으른로드 된 "세금"콜렉션에 액세스하려고 할 때 오류가 발생했기 때문에이 코드를 주석 처리했습니다. 세션을 열어두면 코드가 작동합니다. 좋아요, 당신의 디자인에서, 제가 그 방법 밖에 서 세션을 주입해야한다는 것을 이해합니다. 권리? – BlueBird

+0

네, 간단합니다. 앞으로는 요청간에 세션을 처리하고 주입하는 적절한 컨텍스트를 고려하는 것이 좋습니다. 하지만 그것은 단지 당신이 사용하고있는 프레임 워크에 달렸습니다. 예를 들어 Java (Hibernate and Spring)로 작업하고, Spring은 저에게 세션을 주입하고 요청별로 트랜잭션을 처리합니다. –

+0

ASP.NET webapp을 사용 중입니다. 나는 저장소와 UI 레이어 사이에 모델을 전달하는 서비스 레이어를 가지고있다. 희망 서비스 계층에서 세션을 관리해야합니다. 내가 틀렸다면 수정하십시오. – BlueBird

1

항상 세션을 하나만 활성화해야합니다. 두 가지 일반적인 접근 방식이 있습니다 :

  • 항상 요청을 전달하는 서비스 계층이 있습니다. 이 서비스 계층은 세션 처리 (및 트랜잭션 처리)를 담당합니다. 세션 계층에서 모든 비즈니스 로직을 처리해야 항상 세션을 유지할 수 있습니다. UI에 필요한 모든 것을로드하고 응답의 일부로 리턴해야합니다. 예 :nhibernate를 사용하는 간단한 요청 응답 서비스 계층의 경우 http://davybrion.github.com/Agatha/.
  • 웹 요청 당 세션이 있어야합니다. 이것은 대개 컨트롤러 메소드가 호출되기 전에 세션 (및 트랜잭션)을 열고 이후에 트랜잭션을 커밋하는 작업을 포함합니다. 보통 이것은 세션을 필요로하는 메소드에 두는 속성을 사용하여 처리됩니다. 내 머리 꼭대기에서 완전한 모범을 보일 수는 없지만 하나의 대중적인 접근법이 NHibernate 3.0 Cookbook에 설명되어 있음을 알고 있습니다.
0

웹 응용 프로그램에서 요청 당 세션 패턴을 사용한다고 가정하면 가장 쉬운 해결책은 NHibernateHelper.OpenSession 메서드를 수정하여 요청에 대한 현재 세션을 반환하는 것입니다. 이 작업을 수행하려면 using 블록에 세션 액세스를 래핑 할 수 없으며 대신 global.asax에서 세션 수명을 관리하십시오.

리팩토링하지 않으려는 기존 코드가 많은 경우이 방법을 사용합니다. 리팩토링 할 시간이 있다면 의존성 주입을 사용하여 저장소/쿼리 객체에 ISession을 주입해야합니다.