2011-07-15 31 views
5

此问题旨在成为软件/平台不可知的。我只是在寻找通用的SQL代码。获取存储在RDBMS中的对象的树的最佳方法

考虑下面的表(例如的缘故很简单):

 
Table: Authors 
id | name 
1 | Tyson 
2 | Gordon 
3 | Tony 
etc 

Table: Books 
id | author | title 
1 | 1  | Tyson's First Book 
2 | 2  | Gordon's Book 
3 | 1  | Tyson's Second Book 
4 | 3  | Tony's Book 
etc 

Table: Stores 
id | name 
1 | Books Overflow 
2 | Books Exchange 
etc 

Table: Stores_Books 
id | store | book 
1 | 1  | 1 
2 | 2  | 4 
3 | 1  | 3 
4 | 2  | 2 

正如你所看到的,有Book S和Author S,和许多-TO-间的一种一对多的关系Book s和Store s之间有很多关系。

问题一:什么是最好的查询加载一个作者和他们的书籍(和书籍出售)到一个面向对象的程序,其中每一行代表一个对象实例?

问题二:什么是最好的查询加载整个对象树到一个面向对象的程序,其中每一行代表一个对象实例?

这两种情况很容易通过延迟加载来想象。在任何一种情况下,您都可以通过一个查询获取作者,然后只要您需要他们的图书(以及销售图书的商店),您就可以使用另一个查询来获取该信息。

是延迟加载的最佳方式来做到这一点,或者我应该使用连接并在创建对象树时解析结果(试图加载数据)?在这种情况下,为了尽可能简化解析,数据库的最佳连接/目标输出是什么?

据我所知,在急切加载的情况下,我需要在解析数据时管理某种类型的字典或某种类型的索引。这是真的吗?还是有更好的办法?

回答

3

这是一个难以回答的问题。我之前通过编写一个查询将所有内容作为平面表返回,然后遍历结果,创建对象或结构作为最重要的列更改。我认为这比多个数据库调用更好,因为每次调用都会涉及很多开销,不过取决于每个大实体有多少个小实体可能不是最好的。

以下内容可能适用于您的问题1和2。

SELECT a.id, a.name, b.id, b.name FROM authors a LEFT JOIN books b ON a.id=b.author 

(伪代码,程序中的,使DB调用)

while (%row=fetchrow) { 
    if ($row{a.id} != currentauthor.id) { 
     currentauthor.id=$row{a.id}; 
     currentauthor.name=$row{a.name}; 
     } 
    currentbook=new book($row{b.id, b.name}); 
    push currentauthor.booklist, currentbook; 
    } 

[编辑]我才意识到我没有回答你问题的第二部分。根据商店数据的大小以及我打算如何使用它,我要么

在循环浏览书籍/作者之前,请将整个商店表糅合到我的程序中的一个结构中,就像书/笔者结构之上,而是由STOREID索引,然后每次我读了一本书记录的时间进行查找在结构和存储到存储表

参考,或者,如果有许多商店,

加入存储到书籍上并具有额外的嵌套循环,以便在添加书籍的代码部分中添加商店对象。

这里有一个相关的维基百科文章:http://en.wikipedia.org/wiki/Object-relational_impedance_mismatch

我希望帮助!

+0

你的伪代码给了我一个局部变量作用域的想法。只要我告诉数据库根据一个已知标准对输出进行排序(例如作者和书籍,如你的示例),那么我不必保留本地索引/对象字典,因为我可以引用“ currentAuthor”。 – KPthunder

+0

是的,就是这样。您可能甚至不需要告诉数据库通过a.id对列进行排序,因为它将按照该顺序返回它们,除非您告诉它以其他方式排序。 (我不确定数据库是否能够保证这种行为,但这就是他们的行为。) – ratsbane

+1

这里有一个后续问题。如果“书籍”和“作者”也是多对多的(除了“书籍”和“商店”),怎么办?然后我需要一个应用程序端索引/字典,对吧? – KPthunder

1

下面是一些T-SQL让你开始:

1.

选择a.name,b.title从作者的联接书籍B关于a.id = b.author

2.

选择a.name,b.title,从作者一个 加入图书b s.name 上a.id = b.author 加入Stores_Books SB上sb.book = b.id 加入商店s上s.id = sb.store

2

在OO程序中,您不使用SQL,而是让您的Persistence机制无形地完成它。解释如下:

如果你有一个面向对象的程序,那么你需要一个对象模型,它可以无差别地表示Author,Book和Store的概念。然后你有一个“对象/关系映射”问题。不知何故,你想使用SQL从数据库中获取数据,但自然与你的对象一起工作。

在Java世界中,我们使用Java Persistence API(JPA)来完成这项工作。你实际上并没有编写SQL,而是只是“注释”Java类来表示“这个类对应于该表,该属性对应该列”,然后对JOIN做一些有趣的事情,并且实际上可以选择Lazy或渴望加载,因为它很有意义。

所以,你可能最终得到一个Author类(我使公共这里为简洁的属性,在现实生活中,我们有私有的属性和getter和setter。

@Entity 
public Class Author { 
    public int id; 
    public String name; 
    // more in a minute 

那类被注释为一个实体因此JPA会将对象中的对象与对应表中的列匹配起来,注释具有更多的功能,因此您可以指定属性名称和列中不完全匹配的映射;映射(如

PUBLISHED_AUTHOR => Author, 
    FULL_NAME => name 

Now JOINS和关系怎么样?笔者类有书籍

@Entity 
    public Class Author { 
    public int id; 
    public String name; 
    public List<Book> books; 

和Book类的集合有一个是它的作者

@Entity 
    public Class Book { 
     public int id; 
     public String title 
     public Author author 

JPA实体管理类提取使用find方法的书的实例(I”属性会不会细讲这里)

int primaryKey = 1; 
    Book aBook = em.find(primaryKey); // approximately 

现在你的代码可以去

aBook.author.name 

你永远不会看到SQL被用来获取Book数据的事实,并且当你要求作者属性也获取了作者数据时。一个SQL JOIN可能已经被使用了,你不需要知道。您可以通过更多注释来控制提取是Eager还是Lazy。

同样

int primaryKey = 2 
    Author author = em.find(primaryKey); 

    author.books.size() ; // how many books did the author write? 

我们得到的所有书籍列表以及作者的其他数据,SQL发生的事情,我们没有看到它。

+0

我知道像Hibernate/JPA这样的对象关系映射器,但我更喜欢从零开始进行急切加载的最佳方式。 – KPthunder

+0

+1为详细的答案...做得好! – tzup

+0

不错的介绍!但是,哪些注释控制着“抓取是Eager还是Lazy”?如何使用它以及在哪里指定?我怎样才能从数据库中获得所有作者的列表来显示他们让我们说在JTree中?那么,如何简单地获得所有商店的书籍来自某个作者的书籍?我看到了太多的问题。 – Dime

相关问题