2011-07-15 34 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

相關問題