2009-09-23 230 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的类型。无赖......