2011-01-10 91 views
2

我正在研究MVC中的BLOG功能。我需要能夠創建'博客評論'。因此,每個評論可能有父評論等LINQ親子關係

鑑於表 「備註」: CommentId - > INT - >身份自動增量 帖子ID - > INT 的ParentId - > INT 評論 - >字符串

alt text

有沒有辦法獲得由CreateDate和ParentId定購的給定文章的評論列表?

或者您可能會建議更好的餐桌設計。插入Post Comments這樣的最佳設計是什麼?

我正在使用實體框架。

感謝

+0

您是否使用ORM(例如實體框架,NHibernate等)? – DaveParsons 2011-01-10 09:17:56

+0

實體框架 – ShaneKm 2011-01-10 09:30:45

回答

3

我想我明白你想要做什麼。讓我看看我是否已經明白了。

給定一個選定的PostID您希望返回所有註釋,以便在創建順序中返回頂級註釋(即無父項),並且所有子註釋均按創建順序在每個父項之後並在下一個無關父註釋之前返回。是對的嗎?

我創建了下面的類和測試數據:

public class Comment 
{ 
    public int CommentId { get; set; } 
    public int PostId { get; set; } 
    public int? ParentId { get; set; } 
    public string Content { get; set; } 
} 

var comments = new List<Comment>() 
{ 
    new Comment() { PostId = 2, CommentId = 1, }, 
    new Comment() { PostId = 2, CommentId = 2, ParentId = 1, }, 
    new Comment() { PostId = 2, CommentId = 3, }, 
    new Comment() { PostId = 2, CommentId = 4, ParentId = 1, }, 
    new Comment() { PostId = 2, CommentId = 6, ParentId = 5, }, 
    new Comment() { PostId = 2, CommentId = 7, ParentId = 1, }, 
    new Comment() { PostId = 2, CommentId = 8, ParentId = 3, }, 
    // PostId = 3 to test the filter is working 
    new Comment() { PostId = 3, CommentId = 9, }, 
    // Move this last to test the ordering is working 
    new Comment() { PostId = 2, CommentId = 5, ParentId = 3, }, 
}; 

我假定CommentId會自動遞增,以便它可以被用來確定的創建順序。

所以,如果我理解你的要求,你想下面的輸出順序:

id == 1 [pid == ] 
id == 2 [pid == 1] 
id == 4 [pid == 1] 
id == 7 [pid == 1] 
id == 3 [pid == ] 
id == 5 [pid == 3] 
id == 6 [pid == 5] 
id == 8 [pid == 3] 

需要執行的查詢是這樣的:

var postId = 2; 

var childCommentsLookup = 
    (from c in comments 
    where c.PostId == postId 
    orderby c.CommentId 
    select c).ToLookup(x => x.ParentId); 

此查詢不責令評論,但不會強制執行單個查詢以便在數據庫中執行並返回與postId關聯的所有註釋。

現在有兩種方法以正確的順序獲得評論。

首先,遞歸lambda表達式:

//Must declare this as null to allow recursive calling of the lambda. 
Action<int?, ILookup<int?, Comment>> output = null; 

output = (p, l) => 
{ 
    foreach (var c in l[p]) 
    { 
     Console.WriteLine("id == {0} [pid == {1}]", c.CommentId, c.ParentId); 
     output(c.CommentId, l); 
    } 
}; 

output(null, childCommentsLookup); 

其次,你可以使用一個迭代的方法來簡單地得到,在正確的順序意見的IEnumerable<Comment>:如果你現在

public static IEnumerable<Comment> OrderCommentsRecursively(
    int? parent, ILookup<int?, Comment> lookup) 
{ 
    foreach (var c0 in lookup[parent]) 
    { 
     yield return c0; 
     foreach (var c1 in OrderCommentsRecursively(c0.CommentId, lookup)) 
     { 
      yield return c1; 
     } 
    } 
} 

foreach (var c in OrderCommentsRecursively(null, childCommentsLookup)) 
{ 
    Console.WriteLine("id == {0} [pid == {1}]", c.CommentId, c.ParentId); 
} 

, '要創建一個迭代器函數我會更進一步做出一個很好的方法來直接返回結果:

public static IEnumerable<Comment> GetRecursivelyOrderedCommentsByPostId(
    IEnumerable<Comment> comments, int postId) 
{ 
    return OrderCommentsRecursively(null, 
     (from c in comments 
     where c.PostId == postId 
     select c).ToLookup(x => x.ParentId)); 
} 

foreach (var c in GetRecursivelyOrderedCommentsByPostId(comments, postId)) 
{ 
    Console.WriteLine("id == {0} [pid == {1}]", c.CommentId, c.ParentId); 
} 

從這兩/三種方法的結果是:

Lambda Expression: 
id == 1 [pid == ] 
id == 2 [pid == 1] 
id == 4 [pid == 1] 
id == 7 [pid == 1] 
id == 3 [pid == ] 
id == 5 [pid == 3] 
id == 6 [pid == 5] 
id == 8 [pid == 3] 

Iterator Call: 
id == 1 [pid == ] 
id == 2 [pid == 1] 
id == 4 [pid == 1] 
id == 7 [pid == 1] 
id == 3 [pid == ] 
id == 5 [pid == 3] 
id == 6 [pid == 5] 
id == 8 [pid == 3] 

Query & Iterator Call: 
id == 1 [pid == ] 
id == 2 [pid == 1] 
id == 7 [pid == 1] 
id == 4 [pid == 1] 
id == 3 [pid == ] 
id == 5 [pid == 3] 
id == 6 [pid == 5] 
id == 8 [pid == 3] 

我希望這有助於。

0

如果你有這樣的自我關係基本上你有樹結構,正水平。您無法在一個查詢中查看所有內容,但必須爲每個級別查詢。

解決方法是創建一個logicalPath列,其中包含父行的所有id,以便註釋id 6在該列中具有(3; 1)。訣竅是始終保持正確(最好是觸發器)。如果最常見的是隻有一個或兩個級別,我會保持簡單並創建每個級別的查詢

0

您可能在這裏過度思考的事情。

所有評論都屬於某篇博文。您懷疑是否需要爲他們分頁,因此一次獲得所有帖子的評論以及評論本身之間的關係僅用於渲染是非常安全的。也就是說,您將獲得post.Comments,然後使用它們的回覆呈現comments.Where(x => x.Parent == null).OrderBy(x => x.CreateDate)遞歸。

+0

如何回覆已有評論的評論。您可以發表評論 – ShaneKm 2011-01-10 11:54:46

+0

@Shane Km不要回復和父親評論一樣的帖子ID?因此,所有屬於帖子的評論(例如文章)都可以通過PostID獲取? – Arunas 2011-01-10 13:26:23

1

讓我們假設你有2層深的評論(大多數網站沒有超過2個層次,真的不需要有更深的層次)。

你可以在你的視圖下(我假定認爲是強類型早報):

<% foreach(var comment in Model.Comments.Where (c=>c.ParentId == null)) { %> 
    <%: comment.Text %} 
    <% if (Model.Comments.Count(c=>c.ParentId == comment.Id) > 0) {%> 
     <% foreach (var child in Model.Comment.Where(c=>c.ParentId == comment.Id)) {%> 
     <%: child.Text %> 
     <% } %> 
    <% } %> 
<% } %> 

如果你願意,你可以繼續添加更多的層面是這樣的。

希望這會有所幫助。