【问题标题】:Persistence classes in QtQt 中的持久化类
【发布时间】:2009-09-23 20:20:05
【问题描述】:

我正在将一个中型 CRUD 应用程序从 .Net 移植到 Qt,并且我正在寻找一种用于创建持久性类的模式。在 .Net 中,我通常使用基本方法(插入、更新、删除、选择)创建抽象持久性类,例如:

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 解决此问题的提示或指向一些参考资料?


更新:

根据 Harald 的线索,我实现了一个与上述 .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 版本中很容易发现和理解。

你有什么想法可以让它变得更好吗?

【问题讨论】:

    标签: sql qt orm


    【解决方案1】:

    据我所知,没有任何现成的东西可以直接在 qt 中提供给这个设施。有一些可能的方法。

    • 将字段实现为 Q_PROPERTY,然后通过 Metaclass 系统反映并可用于实现通用 DAO 功能

    • 您仍然可以使用 QSqlTableModel,但将写入与事务封装在一起,如果事务失败,请从数据库中刷新模型。可行性取决于您在模型中保存的数据的大小。

    我们目前使用基于 TableModel/QSqlRecord 的方法进行读写,我们的系统中没有完成 ORM 映射。我一直在尝试设计一种更通用的方法,但目前我们必须进行的重构工作成本很高。

    此链接http://giorgiosironi.blogspot.com/2009/08/10-orm-patterns-components-of-object.html 与 Qt 无关,但很好地概述了实现模式

    【讨论】:

    • 使用您的提示和链接作为起点,我已经发布了我的解决方案实现。请告诉我你的想法。
    【解决方案2】:

    如果您想要一个仅依赖于 Qt 并建立在 Qt 的元对象系统上以提供自省的 ORM,您可以考虑尝试QDjango。在模型级别的基本创建/更新/删除操作之上,它提供了一个查询集模板类(以 django 的查询集为模型),它允许构建相当复杂的查找。 QtScript 集成也在进行中。

    【讨论】:

      【解决方案3】:

      Tegesoft 最近发布了一个名为CAMP 的库的新版本,它提供了您在.Net 中使用的C++ 运行时反射。我认为这将使您能够像在 .Net 中一样实现您的应用程序。

      【讨论】:

      • 它看起来很有希望,但如果我可以在纯 Qt 中解决问题,我不想将提升作为依赖项。
      【解决方案4】:

      还有一个新的开源 ORM C++ 库:QxOrm。 QxOrm 基于QtSql Qt 模块与数据库通信,boost::serialization 以xml 和二进制格式序列化您的数据。该网站是法文的,但快速示例代码和教程代码是英文的(翻译正在进行中......)。

      【讨论】:

        【解决方案5】:

        ...还有一个新的 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。

        【讨论】:

          【解决方案6】:

          这似乎是一项出色的技术。但是,我在让我的原型编译 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()'函数(在一个单独的目录中)试图从数据库中读取一条记录。当我更改模型类头文件时,'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&lt;std::string&gt;() 等,似乎都没有任何效果......不得不恢复为基于Qt 的类型。可惜了....

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-25
            • 2014-11-27
            • 1970-01-01
            相关资源
            最近更新 更多