2010-05-05 2 views
14

콜렉션 인 프로퍼티를 가진 루트 오브젝트가 있습니다. 예를 들어Hibernate 루트의 프로퍼티로서의 IQueryable 콜렉션

:

나는 부모로부터 직접 수집 떨어져 페이징 및 필터링을 실행할 수 있도록 된 IQueryable입니다 컬렉션을 반환하는 것입니다 내가 달성하고 싶다
I have a Shelf object that has Books. 

// Now 
public class Shelf 
{ 
    public ICollection<Book> Books {get; set;} 
} 

// Want 
public class Shelf 
{ 
    public IQueryable<Book> Books {get;set;} 
} 

.

var shelf = shelfRepository.Get(1); 

var filtered = from book in shelf.Books 
       where book.Name == "The Great Gatsby" 
       select book; 

나는 NHibernate에 의해 구체적으로 실행하는 쿼리를 갖고 싶어 아니라 전체 모음을 넣은 다음 (나는 ICollection에를 사용할 때 현재 일어나는입니다) 메모리에 구문 분석 모두를 얻을.

이 추론은 내 컬렉션이 거대하고 수만 건의 레코드가 될 수 있으며 모든 쿼리가 내 데이터베이스를 깨뜨릴 수 있다고 추론합니다.

NHibernate가 내 클래스에서 IQueryable을 볼 때 수행 할 작업을 알 수 있도록이 작업을 암시 적으로 수행하고 싶습니다.

NHibernate의 LINQ 공급자를 살펴 보았습니다. 현재 대규모 컬렉션을 가져 와서 자체 저장소로 분할하여 필터링 및 호출을 명시 적으로 호출 할 수 있습니다.

LINQ To SQL은 내가 말하는 것과 비슷한 것을 제공합니다.

답변

12

저는 비슷한 문제에 대한 해결책을 제시하려고 노력해 왔습니다.

ISession.FilterCollection을 사용하여 엔티티에서 컬렉션을 필터링 할 수 있습니다. 이것은 카운트, 페이징, 조건 추가 등을 할 수있는 추가적인 IQuery를 생성합니다.

따라서, 예를 들어 (FilterCollection 내 쿼리가 조금 떨어져있을 수 있습니다,하지만 당신은 아이디어를 얻어야한다) : 그러나,

ISession session = GetSession(); 
var shelf = session.Get<Shelf>(id); 
var books = session.FilterCollection(shelf.Books, "where Name = :title").SetString("title", "The Great Gatsby").List<Book>(); 

그 문제가 있습니다를 :

  1. 소비자가 코드를 실행하는 경우 ISession.CreateFilter에 액세스해야하거나 이 필요하고 쿼리를 사용하는 리포지토리에 메서드를 만들려면 쿼리 (페이징 또는 기타 정보). 행성에 실제로 가장 섹시한 건.
  2. 원하는 LINQ가 아닙니다.

불행히도 NHibernate로 원하는 것을 얻는 방법이 없다고 생각합니다. 당신이 시도하고 싶었지만 경우 가짜, 그들은 나에게 플랫 떨어질 것으로 보인다 수 :

public IQueryable<Book> FindBooks() { 
    return Resolver.Get<ISession>().Linq<Book>().Where(b => b.Shelf == this); 
} 
:

는 내부적으로이 선반에 대한 자 NHibernate 된 IQueryable에 LINQ를 반환하는 메서드 또는 속성을 추가

어디 사람이 같은 것을 소비 있습니다

var shelf = ShelfRepo.Get(id); 
var books = (from book shelf.FindBooks() 
      where book.Title == "The Great Gatsby" 
      select book); 

왝! 귀하의 도메인 모델을 통해 당신의 끈기의 필요성을 피고 있습니다!

public IQueryable<Book> FindBooks() { 
    return Resolver.Get<IRepository<Book>>().CreateQuery().Where(b => b.Shelf == this); 
} 

여전히 꽤 ㅋ ㅋ : 어쩌면 당신은 좀 덜 악화 저장소를 가짐으로써 런타임에 NHibernate에 실제로 LINQ입니다 된 IQueryable을 방출 할 수있다.

실제 책의 비공개 필드를 래핑하는 사용자 지정 컬렉션 형식 (잠재적으로 IQueryable 구현)을 만들고 해당 필드에 NHibernate를 매핑하십시오. 그러나 ISession.CreateFilter를 사용하여 작업하는 것은 어려운 작업 일 수 있습니다. 현재 세션을 "발견"하고 LINQ 표현식을 CreateFilter 등에서 사용할 수있는 것으로 변환해야합니다. 비즈니스 로직은 여전히 ​​Hibernate에 의존합니다.

아무 것도 실제로는 만족스럽지 않습니다. NHibernate가 컬렉션을 통해 LINQ를 수행 할 수있을 때까지, 비록 그것이 섹시하거나 최적이 아닌 것처럼 보이 더라도 이미 제안 된대로 책 저장소를 쿼리하는 것이 더 낫다.

+0

설명에 철저히 감사드립니다. 나는 당신이 말한 것에 대해 생각해 왔으며, 당신이하는 모든 요점에 동의합니다. 궁금해 NHibernate 3 상자에서 그냥 지원하는 것입니다. –

1

아마도 Nhibernate Linq을 시도해야합니다. 내가 이런 식으로 생각하는 경향이

Session.Linq<Book>().Where(b => b.Name == "The Great Gatsby"); 
+0

"NHibernates Linq 공급자를 살펴 봤는데 현재 큰 컬렉션을 가져 와서 자체 저장소로 분할하여 필터링 및 페이징을위한 명시 적 호출을 할 수 있도록 결정했습니다." –

+2

@Khalid - 왜 이것이 당신을 도울 지 모르겠다. 그것은 당신이 무엇을 요구 정확히 무엇입니까 – Dann

+0

내 질문은 "NHibernate를 IQueryable 속성에 매핑하려면 어떻게해야합니까?" 나는 이미 NHibernate Linq에 대해 알고있다. 이것은 내가 결코 물어 보지 않은 질문에 대한 대답이며, 그것이 제가 투표를 통해 내려진 이유입니다. –

3

: 그것은 당신이 된 IQueryable를 사용하고 같은 일을 할 수 있습니다

집계 뿌리는 일관성의 경계, 그래서 선반은 책에 일관성 정책의 일종을 시행 할 필요가있는 경우 포함되어 있으면 집계 루트 여야합니다. 그런 경우에는 책 세트/콜렉션이 있어야합니다.

선반에서 책으로 일관성을 유지할 필요가 없다면 set/collection 속성을 제거하고 해당 쿼리를 저장소로 옮기는 것이 좋습니다.

또한 페이지 매기기 및 필터링은 도메인 논리와 아무 관련이 없기 때문에 대부분 프레젠테이션에 유용합니다. 그런 다음 리포지토리에 프리젠 테이션 기능을 추가하는 대신 특수한보기를 고려합니다.

var result = Queries.FindBooksByShelf(shelfId,pageSize); 

이러한 쿼리 그들은 특정보기에 가장 가능성이 특정 또는 GUI에보고 등 예측을 반환 할 수 및/또는 일반 SQL로 최적화 될 수있다. 도메인은 도메인 개념에만 초점을 맞 춥니 다.