获取存储在RDBMS中的对象的树的最佳方法
此问题旨在成为软件/平台不可知的。我只是在寻找通用的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之间有很多关系。
问题一:什么是最好的查询加载一个作者和他们的书籍(和书籍出售)到一个面向对象的程序,其中每一行代表一个对象实例?
问题二:什么是最好的查询加载整个对象树到一个面向对象的程序,其中每一行代表一个对象实例?
这两种情况很容易通过延迟加载来想象。在任何一种情况下,您都可以通过一个查询获取作者,然后只要您需要他们的图书(以及销售图书的商店),您就可以使用另一个查询来获取该信息。
是延迟加载的最佳方式来做到这一点,或者我应该使用连接并在创建对象树时解析结果(试图加载数据)?在这种情况下,为了尽可能简化解析,数据库的最佳连接/目标输出是什么?
据我所知,在急切加载的情况下,我需要在解析数据时管理某种类型的字典或某种类型的索引。这是真的吗?还是有更好的办法?
这是一个难以回答的问题。我之前通过编写一个查询将所有内容作为平面表返回,然后遍历结果,创建对象或结构作为最重要的列更改。我认为这比多个数据库调用更好,因为每次调用都会涉及很多开销,不过取决于每个大实体有多少个小实体可能不是最好的。
以下内容可能适用于您的问题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
我希望帮助!
下面是一些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
在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发生的事情,我们没有看到它。
你的伪代码给了我一个局部变量作用域的想法。只要我告诉数据库根据一个已知标准对输出进行排序(例如作者和书籍,如你的示例),那么我不必保留本地索引/对象字典,因为我可以引用“ currentAuthor”。 – KPthunder
是的,就是这样。您可能甚至不需要告诉数据库通过a.id对列进行排序,因为它将按照该顺序返回它们,除非您告诉它以其他方式排序。 (我不确定数据库是否能够保证这种行为,但这就是他们的行为。) – ratsbane
这里有一个后续问题。如果“书籍”和“作者”也是多对多的(除了“书籍”和“商店”),怎么办?然后我需要一个应用程序端索引/字典,对吧? – KPthunder