2011-06-16 91 views
6

我有以下查詢工作它得到的結果我想:NHibernate的QueryOver加入無關實體

int associatedId = 123; 

MyObject alias = null; 

var subQuery = QueryOver.Of<DatabaseView>() 
    .Where(view => view.AssociatedId == associatedId) 
    .And(view => view.ObjectId == alias.ObjectId) 
    .Select(view => view.ObjectId); 

var results = session.QueryOver<MyObject>(() => alias) 
    .WithSubquery.WhereExists(subQuery) 
    .List(); 

DatabaseView已被映射爲實際NHibernate的實體(這樣我就可以QueryOver使用它),但它在HBM映射中不與MyObject關聯。

該查詢使用SELECT ... FROM MyObject WHERE EXISTS(此處爲DatabaseView的子查詢)返回IList。我怎麼能重新寫這個來返回相同的信息,但使用JOIN呢?

回答

7

您可以加入到不相關的實體使用LINQ的NHibernate 3+

有趣的是,你使用join查詢表達式元素:

from type1 in Repository.Query<MyType1>() 
join type2 in Repository.Query<MyType2>() 
on type1.Id equals type2.Id 

注:Repository.Query只是返回來自會話的IQueryable查詢

我希望有一個QueryOver的解決方案,因爲我d並不總是希望在我的域中爲雙向關係建模,但它們對於查詢仍然有用。

此外,您還可以映射使用標準API來訪問=「空操作」雙向關係沒有投入你的POCO類:

http://ayende.com/blog/4054/nhibernate-query-only-properties

+2

這實際上在與兩個'IQueryable'實例連接時起作用。我很驚訝,這與LINQ('Query <>')實現協同工作,但與'QueryOver <>' – Siewers 2011-09-27 18:20:17

1

我意識到這個問題,是5歲,而「正確的「答案肯定是你不能用QueryOver來做到這一點,正如其他答案所表明的那樣。但是,如果你需要這個功能(就像我做的那樣),那麼我找到了一個體面的解決方法。

解決方案是在映射XML中使用帶有原生SQL的「加載器查詢」來生成相關集合(請參閱http://nhibernate.info/doc/nhibernate-reference/querysql.html#querysql-load)。在OP的具體的例子,你會繼續前進,映射你的DatabaseView作爲一個實體的建議,然後寫在你的映射如下:

<class name="MyObject"...> 
    ... 
    <set name="MyViews" inverse="true"> 
     <key column="ObjectId" foreign-key="none"/> 
     <one-to-many class="MyObject"/> 
     <loader query-ref="myObjectViewsLoadQuery"/> 
    </set> 
</class> 

然後,我們只需要定義我們的原始SQL命名myObjectViewsLoadQuery解釋以NH如何加入兩個:

<sql-query name="myObjectViewsLoadQuery"> 
    <load-collection alias="view" role="MyObject.MyViews"/> 
    SELECT view.* 
    FROM DatabaseView view 
    WHERE view.ObjectId = :id 
</sql-query> 

現在,我們可以假裝有一個名爲MyViews與一個「真實」的收集MyObjectDatabaseView在我們的查詢:

MyObject alias = null; 
DatabaseView view = null; 
var results = session.QueryOver<MyObject>(() => alias) 
    .JoinAlias(() => alias.MyViews,() => view) 
    //.Where(() => view.Property == "myValue") // optionally, restrict the view etc. 
    .List(); 

當然,如果你只關心一個「優雅」的查詢,這會遇到很多麻煩。但是,如果您使用QueryOver的原因是您希望能夠接受任意輸入的表達式來過濾您的DatabaseView或各種類似的活動,則此功能非常好。