2014-02-13 187 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

相关问题