2009-09-23 235 views
8

我正在將一箇中等大小的CRUD應用程序從.Net移植到Qt,我正在尋找一種創建持久性類的模式。在.net我通常創建抽象持久類基本方法(插入,更新,刪除,選擇),例如:Qt中的持久化類

public class DAOBase<T> 
{ 
    public T GetByPrimaryKey(object primaryKey) {...} 

    public void DeleteByPrimaryKey(object primaryKey) {...} 

    public List<T> GetByField(string fieldName, object value) {...} 

    public void Insert(T dto) {...} 

    public void Update(T dto) {...} 
} 

然後,我子類它爲特定的表/ DTO的和添加的屬性爲DB表佈局:

[DBTable("note", "note_id", NpgsqlTypes.NpgsqlDbType.Integer)] 
[DbField("note_id", NpgsqlTypes.NpgsqlDbType.Integer, "NoteId")] 
[DbField("client_id", NpgsqlTypes.NpgsqlDbType.Integer, "ClientId")] 
[DbField("title", NpgsqlTypes.NpgsqlDbType.Text, "Title", "")] 
[DbField("body", NpgsqlTypes.NpgsqlDbType.Text, "Body", "")] 
[DbField("date_added", NpgsqlTypes.NpgsqlDbType.Date, "DateAdded")] 
class NoteDAO : DAOBase<NoteDTO> 
{ 
} 

由於.Net反射系統,我能夠實現大量的代碼重用和輕鬆創建新的ORM。

在Qt中做這種東西的最簡單方法似乎是使用QtSql模塊中的模型類。不幸的是,在我的情況下,它們提供的接口太抽象了。我至少需要事務支持和對QSqlTableModel不提供的單個提交進行控制。

你可以給我一些關於使用Qt解決這個問題的提示,或者指點我一些參考資料嗎?


更新:

基於哈拉爾的線索,我實現了一個解決方案,是非常類似於上面的.NET類。現在我有兩個班。

UniversalDAO繼承的QObject並用QObject的 DTO的使用元類型系統處理:

class UniversalDAO : public QObject 
{ 
    Q_OBJECT 

public: 
    UniversalDAO(QSqlDatabase dataBase, QObject *parent = 0); 
    virtual ~UniversalDAO(); 

    void insert(const QObject &dto); 
    void update(const QObject &dto); 
    void remove(const QObject &dto); 
    void getByPrimaryKey(QObject &dto, const QVariant &key); 
}; 

和通用SpecializedDAO其投射從UniversalDAO獲得適當類型的數據:

template<class DTO> 
class SpecializedDAO 
{ 
public: 
    SpecializedDAO(UniversalDAO *universalDao) 
    virtual ~SpecializedDAO() {} 

    DTO defaultDto() const { return DTO; } 

    void insert(DTO dto) { dao->insert(dto); } 
    void update(DTO dto) { dao->update(dto); } 
    void remove(DTO dto) { dao->remove(dto); } 
    DTO getByPrimaryKey(const QVariant &key); 
}; 

使用上面,我宣佈具體的DAO類如下:

class ClientDAO : public QObject, public SpecializedDAO<ClientDTO> 
{ 
    Q_OBJECT 

public: 
    ClientDAO(UniversalDAO *dao, QObject *parent = 0) : 
     QObject(parent), SpecializedDAO<ClientDTO>(dao) 
    {} 
}; 

從內ClientDAO我必須設置一些數據庫信息UniversalDAO。這就是我的實現變得醜陋,因爲我不喜歡這樣寫道:

QMap<QString, QString> fieldMapper; 
fieldMapper["client_id"] = "clientId"; 
fieldMapper["name"] = "firstName"; 

/* ...all column <-> field pairs in here... */ 

dao->setFieldMapper(fieldMapper); 
dao->setTable("client"); 
dao->setPrimaryKey("client_id"); 

我這樣做是在構造函數,因此它在有人通過標題瀏覽乍一看是不可見的。在.Net版本中,很容易發現和理解。

你有什麼想法可以讓它變得更好嗎?

回答

5

據我所知,沒有什麼東西可以直接在qt中給這個設施。有一些可能的方法。

  • 貫徹領域Q_PROPERTY中,然後通過元類系統的反射,可用於實現通用的DAO功能

  • 你仍然可以使用與QSqlTableModel但封裝與交易寫道,如果一個交易失敗,請從數據庫中刷新模型。可行性取決於您在模型中保存的數據的大小。

我們目前使用的閱讀和寫作的TableModel/QSqlRecord爲基礎的方法,還有在我們的系統中沒有進行任何ORM映射。我一直在試圖設計一個更通用的方法,但我們現在必須做的重構工作目前代價很高。

此鏈接http://giorgiosironi.blogspot.com/2009/08/10-orm-patterns-components-of-object.html不是Qt的相關,但實施方式

+0

以您的提示和鏈接爲出發點,我已經發布了我的解決方案實施。請告訴我你的想法。 – zarzych 2009-10-01 18:42:57

2

Tegesoft近日發佈其庫的新版本命名爲CAMP一個很好的概述提供C++運行時反射,你正在使用的.NET。我想這會讓你像在.NET中做的那樣實現你的應用程序。

+0

它看起來很有希望,但如果我可以在純粹的Qt中解決問題,我不想拉昇爲依賴。 – zarzych 2009-10-01 18:42:05

2

還有一個新的開源ORM C++庫:QxOrm。 QxOrm基於QtSql Qt模塊與數據庫通信,boost :: serialization以xml和二進制格式序列化您的數據。該網站是法文的,但是快速示例代碼和教程代碼是英文的(翻譯正在進行......)。

3

如果你想要一個僅依賴於Qt的ORM,並且建立在Qt的元對象系統上以提供自信,你可以考慮嘗試QDjango。在模型級的基本創建/更新/刪除操作之上,它提供了一個查詢集模板類(模仿django的查詢集),它允許構建相當複雜的查找。 QtScript集成也在進行中。

1

...還有一個新的Qt ORM:QST: QsT SQL Tools(最新的穩定版本 - 0.4.2a版本)。 QST提供了生成簡單SQL查詢的機制:SELECT,INSERT,DELETE,UNPDATE和EXECUTE。版本0.4使用T-SQL;新版本 - 0.5 - 默認會使用PostgreSQL。你會發現,這個ORM基於原始的,不尋常的概念。例如,它與Qt Interview系統集成在一起,因此您可以輕鬆設置視圖表示(列寬,標題)。

有0.3和0.4版本的示例項目:TradeDB 0.3,TradeDB 0.4。 TradeDB 0.4應該對開始學習QST有用。

0

這似乎是一種很好的技術。然而,我有一些問題讓我的原型編譯n鏈接....

我已經實現了基本的描述,並調用DAO類來檢索我的一個DB駐留對象的實例。

下面是調用此這些模型類的語句:

_db = <create QSqlDatabase>; 

    dao = new UniversalDAO (_db); 

    AddressDAO * aDAO = new AddressDAO (dao); 
    Address addr = aDAO->getByPrimaryKey(QVariant(1)); 

在我的一個AddressDao。CPP,我有:

template<class Address> 
Address SpecializedDAO<Address>::getByPrimaryKey(const QVariant &key) 
{ } 

在鏈接時,我得到如下:

undefined reference to 
`SpecializedDAO<Address>::getByPrimaryKey(QVariant const&)' 

我將如何正確地貫徹在SpecializedDAO類中的方法?

更新:

愚蠢的我,我笨,傻,我....我大多了這個工作。這些問題....

  1. 我的模型類(DTO的)被包裹在命名空間和我使用的宏定義和使用這些命名空間。此外,我試圖使用這些類的良好層次結構,並發現moc具有包裝在命名空間中的類層次結構的問題... ...

  2. 我發現模板類的函數定義需要在頭文件中 - 不能在單獨的編譯單元中。

  3. qmake在跨越庫邊界時不會很好地處理(頭文件)依賴關係。我有我的模型的東西在共享庫和'main()'函數(在一個單獨的目錄中)試圖從數據庫中讀取記錄。 「主()」 C文件沒有得到重新編譯,當我改變了我的模型類的頭文件...

以下是詳細信息:

在SpecializedDAO.h:

template<class DTO> 
DTO SpecializedDAO<DTO>::getByPrimaryKey(const QVariant &key) 
     throw (FlowException) 
{ 
    DTO obj; 
    dao->getByPrimaryKey(static_cast<QObject &> (obj), key); 
    return obj; 
} 

在UniversalDAO.cpp:

void 
UniversalDAO::getByPrimaryKey (QObject & dto, const QVariant & key) 
{ 
    <retrieve properties from 'dto' n build up QSqlQuery> 
    <execute QSqlQuery 'SELECT...' to retrieve record> 
    <call dto.setProperty() on all fields> 
} 

電流突出問題是在物業類型使用用戶定義類型的我DTO課程。我試圖使用std::stringQString,但不管我試過(Q_DECLARE_METATYPE(std::string)qRegisterMetaType<std::string>()等,沒有任何東西似乎工作....不得不恢復到基於Qt的類型。無賴......