2010-06-23 54 views
0

我一直試圖過濾幾個小時的子對象的集合失敗,並最終拋出我的手!我是NHibernate的新手,希望對此有幾點指導。我已經嘗試過各種ICriteria等,但沒有運氣。我只是沒有得到它。如何使用NHibernate有效地過濾屬性的集合

我有一個父對象「發佈」與子對象的集合'評論'。該集合被映射爲一個具有註釋側的反轉集合。

什麼我試圖做的是與「Comment.Approved」

實體類的相關部分的狀態枚舉值只返回意見如下:

public class Post 
{ 
    public virtual Guid Id { get; protected set; } 
    private ICollection<Comment> _comments; 
    public virtual ICollection<Comment> Comments 
    { 
     get { return _comments; } 
     protected set { _comments = value; } 
    } 
} 

public class Comment 
{ 
    public virtual Guid Id { get; protected set; } 
    public virtual Post Post { get; set; } 
    public virtual CommentStatus Status { get; set; } 

} 

我的檢索代碼看起來像這樣的時刻:

var Id = __SomeGuidHere__; 
var post = _session 
      .CreateCriteria<Post>() 
      .Add(Restrictions.Eq("Id", Id)) 
      .UniqueResult<Post>(); 

var comments = _session.CreateFilter(post.Comments, "where Status = :status").SetParameter("status", CommentStatus.Approved).List<Comment>(); 

雖然這部作品的SQL不會出現是非常有效的,我希望能夠翻譯下面的SQL中類似的HQL東西或某些類型的的ICriteria:

SELECT * FROM posts p LEFT JOIN comments c ON p.PostId = c.PostId AND c.Status = 0 WHERE p.PostId = '66a2bf13-1330-4414-ac8a-9d9b00ea0705'; 

我看了一下有關這種類型的查詢在這裏,沒有他們的各種答案似乎是解決這一具體情況。

這裏可能有一些非常簡單的東西我很想念,但我現在太累了,現在看不到它。希望NHibernate能更好地指出我的方向。

謝謝你的時間。

編輯:仍然在努力,這裏的一些答案是好的,我開始認爲我的後實體需要重新考慮執行過濾本身,或者我應該實現一個ViewModel來過濾我想要的評論。然而,問題仍然存在,即使只是從學術的角度來看。

我已經更新了選擇,以HQL和嘗試:

var post = _session 
      .CreateQuery("select p from Post as p left join fetch p.Comments as c where p.Id = :id and c.Id in (select ac from p.Comments ac where ac.Status = :status)") 
      .SetParameter("id", Id) 
      .SetParameter("status", CommentStatus.Approved) 
      .UniqueResult<Post>(); 

這隻要一個帖子有經批准的評論作品,否則我沒有得到任何職位,由於生成的SQL使用「AND」在where子句。

有人嗎?我現在很難過!

更新:感謝所有已回覆的人,這已經很有用,迫使我重新評估模型的某些部分。由於評論最常使用評論作爲帖子的子女,因此在查看帖子時,只有批准的評論才能在此場景中查看。在我能想到的大多數其他場景中,都可以直接訪問並按狀態進行過濾,這種狀態當然很簡單。

我已經更新我的映射只加載批准職位(在FluentNHibernate)如下過濾所有帖子>評論加載:

HasMany(x => x.Comments).Where(x => x.Status == CommentStatus.Approved) 
      .AsSet() 
      .Inverse() 
      .KeyColumn("PostId") 
      .ForeignKeyConstraintName("PostComments") 
      .OrderBy("CreatedOn") 
      .Cascade.AllDeleteOrphan(); 

我希望我可以全部標記爲答案,因爲所有的貢獻我的工作這件事情,但彼得是第一個指出,我可能錯誤地考慮模型。

感謝所有。

+0

你想解決什麼問題(除了好奇心)?我的猜測是評論經審覈後獲得批准。有效評論將始終獲得批准;垃圾郵件或冒犯者將被刪除。所以我希望絕大多數評論都能得到批准。如果是這種情況,那麼將它們全部返回(在FK上選擇)並在UI中進行篩選可能比預先篩選它們更有效。 – 2010-06-23 15:24:02

+0

實際上,垃圾評論將不會被刪除,因爲它們將被用於貝葉斯過濾器中,以便確定什麼是垃圾郵件以及未來什麼是垃圾郵件,所以我認爲很可能選擇所有評論發佈後,UI過濾可能變得非常低效。 – 2010-06-23 16:06:02

+0

但是我又是新來的,所以我可能會說垃圾:) – 2010-06-23 16:06:48

回答

0

根據我的說法,SQL非常適合您所描述的內容。

數據庫擁有自己的優化器,並知道如何將數據有效地傳送到您的家門口。

+0

感謝您的評論,我希望Post對象有一個很好的過濾註釋集,而不必在代碼的其餘部分使用第二個對象(var註釋)。這可能只是我在行動中的保持力:)如果有一個讓我保持模型的選擇,我寧願擁有它。它讓我感到難過,即帖子對象仍然有我不想掛的評論! – 2010-06-23 06:07:37

+1

然後危險的是post對象中的「comments」字段在不同情況下會有不同的含義,這很快會變得複雜。考慮添加一個getApprovedComment()或其他東西。通常你只需要一次請求中的這些東西,然後延遲加載就會很有效率。如果您確實需要多次,則可以使用該方法緩存結果。 – 2010-06-23 06:20:22

+0

嗯,這很有趣,我的知識不能滿足於此,請你再解釋一下。我認爲這些評論具有不同的含義,也就是說,在這種情況下實際上是批准的評論,也可能是管理方案中的「垃圾評論」,「狡猾的評論」和批准的評論。你會建議,也許後對象應該有幾個集合,每個集合都有不同的映射? – 2010-06-23 06:32:14

0

我認爲這將很好地工作:

var comments = 
_session.CreateCriteria<Comment> 
.CreateAlias("Post", "post") 
.Add (Restriction.Eq("Status", status)) 
.Add (Restriction.Eq("post.Id", Id)).List(); 

如果你需要.CreateAlias部分(如果你不需要它,也許Post.Id將工作太,我不舒爾 - 但我不是當然)。

+0

我看到你來自哪裏,但這個查詢只返回評論我真的很喜歡它的集合後過濾對象的任何帖子,如果這是可能的狀態,我想要的。如果沒有,我將不得不忍受我所擁有的,但它似乎應該是直截了當的! – 2010-06-23 06:23:38

+0

在這種情況下,我會在Post類中創建一個屬性,它將返回正確的註釋(過濾註釋屬性) - 但這取決於您的應用程序(如果此「次優」查詢可接受或不可接受) – bernhardrusch 2010-06-23 06:42:44

+0

總的來說,我會先開始實施 - 然後測試它 - 如果性能不好 - 我會開始優化這些情況(沒有過早的優化) – bernhardrusch 2010-06-23 06:44:44

0

我會使用擴展方法IEnumerable<Comment>解決這個問題:

public static IEnumerable<Comment> FilterByStatus(this IEnumerable<Comment> comments, CommentStatus status) 
{ 
    return comments.Where(x => x.Status == status); 
} 

讓NHibernate的回報,那麼整個收集器的過濾需要。

+0

開始認爲這個或者來自bernhardrusch或Peter的其他方法之一可能是我的唯一的選擇。 – 2010-06-23 15:07:38

相關問題