2011-12-22 96 views
2

在我的Java應用程序中,我想實現數據庫操作的抽象層。我不想將我的應用程序綁定到任何類型的數據庫(實現可以是任意的:SQL,XML,基於文檔的,一堆醜陋的文本文件等)DAO設計和數據結構

實體之間有很多關係,大多數的時候,這種關係是一對多的關係。

更新和免責聲明:雖然示例很簡單,但它們只是整個更復雜模型的一部分,它們有可能不適合ORM/SQL模型(這是因爲大量數據:〜幾個當規範化爲關係時,以及由於數據的性質不同,有10億條記錄)。我在這裏詢問實施簡單的關係,但這並不意味着它們構成了唯一的應用問題。

簡化示例以下:

public class Vehicle { 
    String mark; 
    String model; 
    String registrationId; 
} 

public class Depot { 
    String name; 
    String address; 
} 

每個實體有它自己的DAO接口:

public interface VehicleDAO { 
    List<Vehicle> getVehicles(); 
    Vehicle getVehicleByRegistrationId(String registrationId); 
} 

public interface DepotDAO { 
    List<Depot> getDepots(); 
    Depot getDepotByName(String name); 
} 

這些的DAO簡化爲好,只是顯示一些方法,這些方法分離對於特定實體(通過其註冊ID獲得車輛,我不需要知道關於其他實體的任何內容)。

現在有趣的部分來了。 車廠與車輛的關係是一對多。所以我必須在我的實體類和DAO方法中實現這種關係。

現在我有此兩種方法:

  • 地方List<Vehicle>物業內Depot類和填充它,每當我取Depot實例(可能有懶取的改進)。這種方式DAO接口沒有改變。
  • 引入DepotVehicle的特殊標識符,以便實體類獲得附加整數屬性int id;,並且我們向DAO List<Vehicle> getVehiclesForDepot(int depotId)添加方法。這種方法可以通過爲標識符而不是普通整數引入特殊類來加強。

也許還有其他的方法嗎?建模實體之間關係並設計DAO接口以保持數據庫抽象易於使用且不受任何類型數據庫限制的最佳方式是什麼?我不一定會詢問完整和準確的解決方案,而是解決上述問題時的一些原則。

+6

這被稱爲重新發明輪子 - 使用如Hibernate的ORM。 – 2011-12-22 08:48:44

+0

@PetarMinchev使用ORM違反的不被綁定到任何類型的數據庫 – 2011-12-22 08:50:48

+2

的然後使用ORM僅用於數據庫部分的要求之一。另外,我還沒有看到真正的項目中的數據存儲從數據庫變爲「xml」。 – 2011-12-22 08:54:25

回答

1

在您的例子您使用的是本地化的DAO類型的方法,這是更好地定義一套一致的DAO方法來覆蓋這些功能,即

// load object of DAO type T 
<T> load(id) 
// load objects of DAO type T 
List<T> load(List<id>) 
// load all objects of DAO type T 
List<T> find() 
// load multiple objects of DAO type T 
List<T> find(relation) 

等,如果您使用的是一致的id鍵入(例如,long),您可以定義覆蓋基本方法的interface

要加載的關係,你有幾種選擇,這是最好的取決於你的對象及其關係的用法:

  • 使List<T>數據持有者的屬性並填寫爲load()
  • 一部分

這適用於關係,當相關的實體沒有進一步的實體關係的少量。如果他們這樣做,你將不得不部分地加載它們,以防止裝載太多了前面(如你所提到的延遲加載是一種策略。)

  • 使List<T_id>數據持有者的屬性並填寫爲load()一部分

這適用於中等數量的關係,與load(List<id>)方法一起用於訪問相關實體。

對於大數據量的,因爲你提到的是你正在試圖解決這個問題的大頭,你可以斷開的關係一點,並使用DAO的方法,如:

// retrieve related entity id's for this DAO T 
List<id> loadIds(T) 

加載一組(國外)id的實體與數據持有者對象的關係作爲參數傳遞。您的經理/業務/服務層然後使用該id列表來加載下一組實體,可能通過將偏移量傳遞給id列表以及加載實體數量來實現分塊。

// fill entity relations for T2 to this DAO tyoe T 
void fill(T2) 

T::fill()方法將使用上T2 getter方法來獲得:

另外,您可以通過添加DAO方法來填補另一個DAO類型的數據容器對象外交關係脫鉤有關關係的知識以確定相關實體(或它們的id的)加載和一個或多個設置器所需的數據存儲在所述數據T2持有者對象信息。

大部分的這些DAO的負載方法將離開關係數據設置爲null把它留給在以後加載。這當然意味着他們的數據持有者對象獲取者必須能夠處理null值作爲合同的一部分。

+0

謝謝!至於泛型 - 從接口的角度來看,它們可能是有用的,但是當涉及到特定的實現時,這些方法將變得非常龐大。這是因爲不同的實體具有不同的屬性。那麼實際的實現不會被檢查'if(T instanceof X)'充斥嗎? – 2011-12-22 10:33:10

+0

目前我認爲第二種方法(使用id列表來維護關係)是最好的方法。大量數據僅適用於實體的一小部分(車輛的運營數據 - 對於他們我可以使用一點點不同的策略),我寧願堅持使設計更清潔的解決方案。 – 2011-12-22 10:37:52

+0

@pavel_kazlou,你沒有太多使用泛型。如果你的數據模型支持它,只能使用非泛型接口,只有'long','String','List'和你的DAO數據庫類型作爲參數。如果加載的列表不改變你的DAO方法,如果id和數據持有者對象而不是'List's可以返回數組。 (當你處理大量的數據和內存成爲一個問題。) – rsp 2011-12-22 10:47:50