获取存储在RDBMS中的对象树的最佳方法

时间:2011-07-15 05:10:21

标签: sql database object

此问题旨在与软件/平台无关。我只是在寻找通用的SQL代码。

考虑以下(非常简单的例子)表:

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

正如您所看到的,BookAuthor之间存在一对多关系,Book和{{{{}之间存在多对多关系1}} S上。

问题一:将一位作者及其书籍(以及销售书籍的位置)急切加载到面向对象程序中的最佳查询是什么,其中每一行代表一个对象实例?

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

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

延迟加载是执行此操作的最佳方式,还是应该在创建对象树时使用连接并解析结果(试图急切加载数据)?在这种情况下会是什么是数据库的最佳连接/目标输出,以使解析尽可能简单?

据我所知,在急切加载时,我需要在解析数据时管理某些所有对象的字典或索引。实际上是这种情况还是有更好的方法?

3 个答案:

答案 0 :(得分:3)

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

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

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

(伪代码,在您的程序中进行数据库调用)

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

我希望有所帮助!

答案 1 :(得分: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将对象中的atrributes与相应表中的列进行匹配。注释具有更多功能,因此您可以指定属性名称与不完全匹配的列之间的映射;

等映射
    PUBLISHED_AUTHOR => Author,  
    FULL_NAME => name

现在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 Entity Manager类使用find方法获取Book的实例(我在此不再赘述)

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

现在你的代码可以去

   aBook.author.name  

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

类似地

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

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

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

答案 2 :(得分:1)

这是一些让你入门的T-SQL:

1

从作者选择a.name,b.title a a.id = b.author

加入图书b

2

选择a.name,b.title,s.name  来自作者a  在a.id = b.author上加入图书b  在sb.book = b.id上加入Stores_Books sb  在s.id = sb.store

上加入商店