2014-02-13 186 views
2

關於此問題有很多問題,但沒有足夠的確切答案,特別是使用SQL Server,我在這種情況下。選擇所有帖子及其所有標籤

我有3個表格來表示與之相關的博客文章和標籤。我想運行一個查詢,它將獲得所有帖子和每個帖子標籤 - 我需要標籤ID和名稱。結果需要輕鬆地序列化到我的C#類中。我也試圖使用Dapper.net,但這不是最重要的部分。

顯然很多網站都這樣做,我想知道最好的方式,以及它應該如何在現實世界中完成?我可以獲取所有帖子,然後爲每個帖子運行多個查詢,以便返回每個帖子的標籤。但肯定會有更好的方法?

如果我只是想獲得一篇文章,那麼我只會寫多個選擇。一個是帖子,一個是標籤。但我想要所有的帖子。有沒有這樣做的方式,而不復制每個返回的標記行的發佈信息?

如果每個帖子的標籤都被串行化成一個以逗號分隔的列,那麼如何才能同時獲得id和名稱?編碼字符串?

SELECT * FROM dbo.Posts  
SELECT * FROM dbo.Tags 
SELECT * FROM dbo.PostTags 

Posts 
Id Title  Content 
=============================== 
1 First Post First Content 
3 Second  Second Content 

Tags 
Id Name 
============ 
1 C# 
2 SQL 
3 IIS 
4 Steam 
5 OpenID 

PostTags 
PostId TagId 
============= 
1  1 
1  2 
3  3 
3  4 

只需用下面的查詢連接表:

Id Title  Content   Name 
====================================== 
1 First Post First Post  C# 
1 First Post First Post  SQL 
3 Second Post Second Content IIS 
3 Second Post Second Content Steam 
+0

這將是一個非常醜陋的黑客攻擊,但我已經看到了它在生產中使用你沒事與他們合併成一列,然後在C#解析結束之前...?例如,標籤列可能如下所示:「{{{1 ||| C#}}} {{{2 ||| SQL}}}」等等(格式爲{{{ID |||姓名}}} ...) – Ruslan

+0

嗯,我在想,我希望看到什麼最好的做法是關於這種事情 - 我認爲這是相當普遍的事情不是? 我也希望利用Dapper.net(微ORM) - 我不認爲它可以處理之類的事情開箱。 – Ant

+0

這絕對與最佳實踐(特別是當您在討論.NET和OOP以及ORM時)相距甚遠,但由於性能和帶寬的原因,它有時在現實世界中使用(就像許多其他非常黑客的事情一樣)注意事項。另一種可能更好的方式仍然有些過時,但並不像上面那樣醜陋,是要返回多個結果集(不知道Dapper是否可以處理該結果集)。因此,在第一個結果中,標籤列將僅包含以逗號分隔的標籤ID列表,而第二個結果將設置實際的標籤列表(以及它們的含義)。 – Ruslan

回答

0

SELECT p.*, t.Name 
FROM dbo.Posts p 
LEFT JOIN dbo.PostTags pt ON p.id = pt.PostId 
LEFT JOIN dbo.Tags t ON t.id = pt.TagId 

通過重複後的內容爲與它相關聯的每個標籤提供了很多的冗餘數據很顯然很多網站都這樣做,我想知道最好的方法..

最好的方法:沒有一個。

以及它應該如何在現實世界中完成?

實體框架將按照您的建議構建查詢並實現您需要的對象。是的,有重複的數據,但更常見的情況是,重複的數據對於相關數據更好,然後嘗試再次將這些信息重新聯繫起來。優點是代碼更具可讀性,並且更容易以c#語言查詢,具有相關記錄和更改跟蹤(默認情況下)。

Dapper can do the same thing - A parent object with it's children objects。它是faster,但它沒有更改跟蹤,並且這些語句不是c#like,它們(就我所見)直接使用SQL,這使得編寫動態查詢變得更加困難。

但是肯定還有更好的方法嗎?

我不知道更好是。它更有效率,更少的內存開銷,更少的網絡數據包/大小,更易維護,更易讀?

是否有這樣做不復制返回的每個標籤行該發佈信息的一種方式?

是的,你可以寫一個存儲過程返回多個記錄,兌現你的對象,並起來手動。

This sounds like you are trying to optimize something you don't have a problem with.

+0

不,我現在沒有問題,這只是一個技術練習 - 我只是想知道在這個領域是否有一個簡單的解決方案或最佳實踐,但它看起來並不那麼合適!感謝您提供有用的信息;我猜重複數據在低容量下不成問題,標籤的緩存是一個體面的方法,不過它是一個更大的系統。 – Ant

1

這是一個純粹的運動,讓我說的數據是最有可能的量被複制前言本不是什麼大不了的事。儘管如果帖子非常大並且有很多帖子,它確實開始更有意義以避免重複。

此外,使用C#LINQ到SQL或實體框架,對象關係將摸索出適合你和你的Post實體將有一個List<Tag>屬性,您可以訪問。

但是,如果你想推出自己的類型的東西,一個只涉及一個數據庫往返且不重複數據的選項是編寫一個存儲過程,讓你回來2個記錄集(2個獨立的選擇語句)包含發佈內容,另一個包含標籤內容。

然後,創建一個代表Post的C#類,並且只有一個List<Tag>並從存儲的proc結果中提取它將非常簡單。

Create Procedure GetPostTags 
As 

-- We will use the GotTags column here to loop through and get tabs later 
Declare @Posts Table (
    PostID varchar(50), 
    PostTitle varchar(50), 
    PostContent varchar(50), 
    GotTags bit default 0 
) 

/* Assuming you care about the ID's, this will get you all of 
    the tags without duplicating any post content */ 
Declare @PostTags Table (
    PostID int, 
    TagID int, 
    TagName varchar(50) 
) 

-- Populate posts from the main table 
Insert Into @Posts (PostID, PostTitle, PostContent) 
Select * From Posts 

-- Now loop through and get the tags for each post. 
Declare @CurrentPostID int 
Set @CurrentPostID = (Select Top 1 PostID From @Posts Where GotTags = 0) 
While @CurrentPostID Is Not Null 
    Begin 
     Insert Into @PostTags (PostId, TagID, TagName) 
     Select pt.postid, pt.tagid, t.name 
     From Tags t 
      Join PostTags pt 
       On t.id = pt.tagid 
     Where pt.postid = @CurrentPostID 

     -- Set next loop 
     Update @Posts Set GotTags = 1 Where PostID = @CurrentPostID 
     Set @CurrentPostID = (Select Top 1 PostID From @Posts Where GotTags = 0) 
    End 

-- Return 2 recordsets, which are related by the PostID column found in both sets 
Select * from @Posts 
Select * From @PostTags 

我更喜歡這種類型的解決方案,將字符串連接成一個字符串,然後再拆分它們;它使得以這種方式處理數據變得更加容易,允許在C#中使用更多面向對象的方式,並且可以讓標記ID更易於追蹤標籤需要從帖子中刪除或添加到帖子中的情況,而您並不需要由於您已經擁有該ID,因此可以按名稱查找標籤或匹配項。

0

我會寫一個查詢返回多個記錄。我不會擔心過度優化,直到你做一些性能測試。

我不知道關於小巧玲瓏的最近一個一對多或多對一的許多查詢的支持,但你可能想在Insight.Database 4.0簽出新的特點。現在在nuget有一個預發佈版。

退房預發佈文檔。我喜歡一些反饋。

https://github.com/jonwagner/Insight.Database/wiki/Proposed-4.0-Changes

相關問題