01 tutorial QxOrm

Reimpresso de https://www.cnblogs.com/chinasoft/p/16065959.html, apenas para registrar o aprendizado


ORM

O nome completo do ORM é Mapeamento Relacional de Objeto (Object Relational Mapping), que é uma tecnologia de programação usada para realizar a conversão entre dados de diferentes tipos de sistemas em linguagens de programação orientadas a objetos. Na verdade, ele cria um "banco de dados de objetos virtuais" que pode ser usado em linguagens de programação.

A orientação a objetos é desenvolvida com base nos princípios básicos da engenharia de software (como acoplamento, agregação, encapsulamento), enquanto os bancos de dados relacionais são desenvolvidos a partir de teorias matemáticas.Existem diferenças significativas entre os dois conjuntos de teorias. Para resolver esse fenômeno de incompatibilidade, surgiu a tecnologia de mapeamento objeto-relacional.

Entendimento simples, ORM é um mapeamento entre o banco de dados e o objeto:

  • Tabela do banco de dados (tabela) –> classe (classe)
  • Registro (registro, dados de linha) –> objeto (objeto)
  • Campo (campo) –> atributo do objeto (atributo)

Prós e contras de ORMs

vantagem:

  • ORM fornece uma linguagem de consulta orientada a objetos, que permite aos desenvolvedores focar no modelo de objeto sem se preocupar com a estrutura do banco de dados ou semântica SQL.
  • O ORM fornece um grande número de serviços, os desenvolvedores só precisam se concentrar na lógica de negócios, em vez de operações repetidas de CRUD (Criar, Ler, Atualizar, Excluir), que podem reduzir muito o código.
  • Um ORM forçará você a usar o estilo MVC, que geralmente resulta em um código mais limpo e fácil de entender.
  • O ORM possui ferramentas prontas e muitas funções podem ser concluídas automaticamente, como pré-processamento, transações etc.
  • ORM abstrai o banco de dados, então mudar de um banco de dados para outro (por exemplo: de MySQL para PostgreSQL) é fácil.

deficiência:

  • Não importa qual seja a estrutura ORM, é necessário um esforço considerável para aprender e entender.
  • ORM abstrai a camada de banco de dados e os desenvolvedores não conseguem entender as operações relacionadas ao banco de dados subjacente (e SQL).
  • Para consultas complexas, o ORM é difícil de implementar ou o desempenho não é tão bom quanto o SQL nativo.

Estrutura ORM principal

Até agora, os principais frameworks ORM em C++ são os seguintes:

  • LiteSQL: https://litesql.org/
  • ODB: https://www.codesynthesis.com/products/odb/
  • QxOrm:https://www.qxorm.com/qxorm_en/home.html
  • Wt::Dbo: https://www.webtoolkit.eu/wt/doc/tutorial/dbo.html Entre eles, LiteSQL
    e ODB não dependem de uma estrutura específica, enquanto QxOrm depende de Qt e Wt::Dbo depende em peso

Consideração abrangente, se for desenvolvimento C++ puro, você pode optar por usar ODB. Possui uma grande base de usuários, (comparado ao LiteSQL) bom suporte técnico, (comparado ao QxOrm) tempo de compilação curto, (comparado ao Wt::Dbo) fornece mais recursos, mais importante, é fácil de usar e fornece muito abrangente documentação.

Claro, se for desenvolvimento Qt, você também pode optar por usar o QxOrm. Ele suporta quase todos os bancos de dados e também está bem documentado. Além disso, também fornece um editor gráfico - QxEntityEditor, que pode facilmente gerenciar o modelo de dados graficamente.


Sobre QxOrm

QxOrm é uma biblioteca C++ projetada para fornecer aos desenvolvedores C++/Qt a funcionalidade Object Relational Mapping (ORM) (semelhante ao Hibernate em Java, NHibernate em .Net).

  • Página inicial: http://www.qxorm.com/qxorm_en/home.html
  • Download: http://www.qxorm.com/qxorm_en/download.html
  • Manual: http://www.qxorm.com/qxorm_en/manual.html
  • Documentação da aula online: http://www.qxorm.com/doxygen/html/index.html
  • GitHub: https://github.com/QxOrm/QxOrm

Suas principais características incluem:

  • Persistência: Suporta os bancos de dados mais comuns, como SQLite, MySQL, PostgreSQL, Oracle, MS SQL
    Server, MongoDB (com relacionamentos 1-1, 1-n, n-1 e nn).
  • Serialização: formatos JSON, binário e XML.
  • Reflexão (ou introspecção): acesse dinamicamente definições de classe, recupere atributos e chame métodos de classe.
  • Servidor da Web HTTP: servidor da Web HTTP 1.1 multiencadeado independente (suporta SSL/TLS, conexões persistentes, cookies, sessões, respostas agrupadas, despachante/roteador de URL).
  • API JSON: Interoperabilidade com tecnologias diferentes de C++/Qt (serviços da Web REST, aplicativos QML, linguagens de script).

Por padrão, a biblioteca QxOrm depende apenas dos módulos QtCore e QtSql. Se o recurso do servidor da Web QxOrm HTTP estiver ativado, ele também dependerá do módulo QtNetwork. Além disso, alguns recursos também precisam contar com boost (desativado por padrão).


Compilar QxOrm

Entre na página de download do QxOrm, selecione a versão mais recente para baixar, atualmente a mais recente é QxOrm 1.4.8. Após a conclusão do download, descompacte o pacote zip do QxOrm.

Uma introdução a alguns diretórios importantes:

  • doc: Apresenta documentos relacionados do QxOrm.
  • include: Inclui todos os arquivos de cabeçalho (.h) do QxOrm.
  • lib: Diretório da biblioteca, usado para armazenar arquivos .lib e .dll compilados.
  • src: Contém todos os arquivos fonte (.cpp) do QxOrm.
  • test: Contém programas de amostra relacionados ao QxOrm.

As versões históricas do QxOrm e algumas características de cada versão estão registradas no arquivo change.txt.Se você estiver interessado, pode dar uma olhada.

Como CMakeLists.txt, QxOrm.pro e QxOrm.sln são fornecidos no pacote de código-fonte, se você usar CMake, Qt Creator ou Visual Studio, poderá compilar QxOrm rapidamente.

Tome o Qt Creator como exemplo, abra QxOrm.pro e compile-o. Após o sucesso, a biblioteca correspondente será gerada no diretório QxOrm/lib.

Por padrão, isso gerará uma biblioteca compartilhada (biblioteca de vínculo dinâmico); se você deseja gerar uma biblioteca de vínculo estático, é necessário habilitar a opção de compilação _QX_STATIC_BUILD em QxOrm.pri.


QxOrm usa

O QxOrm suporta quase todos os bancos de dados convencionais, como SQLite, MySQL, PostgreSQL, Oracle, MS SQL Server, MongoDB, etc. Para entender rapidamente seu uso, tomamos o SQLite como exemplo para introduzir algumas operações comuns de banco de dados (como adicionar, excluir, modificar e verificar).

Vamos primeiro criar um projeto chamado User. O diretório onde o projeto está localizado está no mesmo nível do diretório de descompactação do QxOrm, e pode ser ajustado de acordo com suas necessidades. O endereço completo de download do código-fonte do projeto.

arquivos de projeto

O arquivo do projeto é representado por User.pro, que contém uma lista de todos os arquivos do projeto (arquivos de cabeçalho, arquivos de origem) e todas as dependências (o arquivo QxOrm.pri contém todas as dependências com Qt e bibliotecas de reforço):

# QxOrm 的通用配置,包含了 Qt 和 boost 库依赖
include($$PWD/../../QxOrm/QxOrm.pri)

CONFIG += console
DEFINES += _BUILDING_USER

# 预编译头文件
!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) {
    
    
    PRECOMPILED_HEADER = precompiled.h
}

# QxOrm 库相关配置
INCLUDEPATH += $$PWD/../../QxOrm/include
LIBS += -L$$PWD/../../QxOrm/lib

# 设置生成的目标名称、添加依赖库
CONFIG(debug, debug|release) {
    
    
    TARGET = Userd
    LIBS += -lQxOrmd
} else {
    
    
    TARGET = User
    LIBS += -lQxOrm
}

# 文件列表
HEADERS += \
    precompiled.h \
    export.h \
    user.h

SOURCES += \
    main.cpp \
    user.cpp

arquivo export.h

Se você usou DLL, acredito que este arquivo não seja desconhecido, ele pode gerenciar a exportação/importação de classes, funções....

O QxOrm usa o mesmo mecanismo para fornecer algumas funcionalidades: portanto, o arquivo export.h é necessário para todos os projetos que usam a biblioteca QxOrm:

#ifndef EXPORT_H
#define EXPORT_H

#ifdef _BUILDING_USER
#define USER_DLL_EXPORT  QX_DLL_EXPORT_HELPER
#else
#define USER_DLL_EXPORT  QX_DLL_IMPORT_HELPER
#endif

#ifdef _BUILDING_USER
#define QX_REGISTER_HPP_USER  QX_REGISTER_HPP_EXPORT_DLL
#define QX_REGISTER_CPP_USER  QX_REGISTER_CPP_EXPORT_DLL
#else
#define QX_REGISTER_HPP_USER  QX_REGISTER_HPP_IMPORT_DLL
#define QX_REGISTER_CPP_USER  QX_REGISTER_CPP_IMPORT_DLL
#endif

#endif // EXPORT_H

arquivo de cabeçalho pré-compilado

A função do arquivo de cabeçalho pré-compilado é melhorar a velocidade de compilação. Em outras palavras, usá-lo pode reduzir o tempo de compilação do projeto.

QxOrm usa o conceito de metaprogramação para fornecer muitas funções, a metaprogramação é cara em tempo de compilação, então use o arquivo precompiled.h para compilar o projeto mais rápido:

#ifndef PRECOMPILED_H
#define PRECOMPILED_H

#include <QxOrm.h>
#include "export.h"

#endif // PRECOMPILED_H

Além disso, há outra vantagem: o arquivo QxOrm.h contém as funções básicas do Qt e bibliotecas de reforço, portanto não há necessidade de escrever instruções como #include <QtCore/QString.h> para usar a classe QString do Qt; da mesma forma, há também não há necessidade de escrever instruções como #include <boost/shared_ptr.hpp> para usar os ponteiros inteligentes da biblioteca boost.

Defina a classe Usuário

No código C++, a classe User corresponde à tabela User no banco de dados e os atributos da classe correspondem a um campo (coluna) na tabela. Portanto, uma instância da classe User no código-fonte C++ corresponde a um registro (linha) na tabela User. Esse mecanismo torna o código-fonte C++ mais fácil de desenvolver e manter.

Defina três propriedades para a classe User, id, name e age:

#ifndef USER_H
#define USER_H

class USER_DLL_EXPORT User
{
    
    
public:
    User() : id(0) {
    
     }
    virtual ~User() {
    
     }

    long id;
    QString name;
    int age;
};

QX_REGISTER_HPP_USER(User, qx::trait::no_base_class_defined, 1)

#endif // USER_H

A macro QX_REGISTER_HPP_USER é necessária para registrar a classe User no contexto do QxOrm:

  • Parâmetro um: Indica a classe atual a ser cadastrada - Usuário.
  • Parâmetro dois: classe base, se não houver classe base, use qx::trait::no_base_class_defined.
  • Parâmetro três: A versão da classe usada para serialização.

No arquivo user.cpp, você precisa implementar qx::register_class(), que é uma função de configuração:

#include "precompiled.h"
#include "user.h"
#include <QxOrm_Impl.h>

QX_REGISTER_CPP_USER(User)

namespace qx {
    
    
    template <> void register_class(QxClass<User> & t)
    {
    
    
        // 注册 User::id <=> 数据库中的主键
        t.id(&User::id, "id");

        // 注册 User::name 属性,使用的 key 是 name,version 是 1。
        t.data(&User::name, "name", 1);

        // 注册 User::age 属性,使用的 key 是 age。
        t.data(&User::age, "age");
    }
}

Assim como QX_REGISTER_HPP_USER, a macro QX_REGISTER_CPP_USER também é necessária para registrar a classe User no contexto de QxOrm.

aplicação básica

Agora, é hora de tentar. Através da classe User, para entender algumas operações básicas no QxOrm:

#include "precompiled.h"
#include "user.h"
#include <QxOrm_Impl.h>

int main(int argc, char *argv[])
{
    
    
    QCoreApplication a(argc, argv);

    // 初始化参数,用于和数据库交互
    qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
    qx::QxSqlDatabase::getSingleton()->setDatabaseName("./Users.db");
    qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
    qx::QxSqlDatabase::getSingleton()->setUserName("root");
    qx::QxSqlDatabase::getSingleton()->setPassword("");

    // 在数据库中创建 User 表
    QSqlError daoError = qx::dao::create_table<User>();

    // 创建 3 个用户
    // 可以使用 std 和 Qt 智能指针:std::shared_ptr、QSharedPointer 等...
    typedef  QSharedPointer<User> UserPtr;
    UserPtr u1;
    u1.reset(new User());
    u1->name = "Jack Ma";
    u1->age = 30;

    UserPtr u2;
    u2.reset(new User());
    u2->name = "Pony";
    u2->age = 25;

    UserPtr u3;
    u3.reset(new User());
    u3->name = "Waleon";
    u3->age = 18;

    // 将所有用户插入容器中
    // 可以使用 std、boost、Qt 和 qx::QxCollection<Key,Value> 中的许多容器
    typedef QVector<UserPtr> VectorUser;
    VectorUser users;
    users.push_back(u1);
    users.push_back(u2);
    users.push_back(u3);

    // 将容器中的所有用户插入到数据库中
    // p1、p2、p3 的 id 属性会自动更新
    daoError = qx::dao::insert(users);

    // 修改第二个用户的信息,并更新到数据库中
    u2->name = "Pony modified";
    u2->age = 38;
    daoError = qx::dao::update(u2);

    // 从数据库中删除第一个用户
    daoError = qx::dao::delete_by_id(u1);

    // 计算用户的数量
    long userCount = qx::dao::count<User>();
    qDebug() << "User Count: " << userCount;

    // 将 id 为 3 的用户取出,并传给一个新变量
    UserPtr userTmp;
    userTmp.reset(new User());
    userTmp->id = 3;
    daoError = qx::dao::fetch_by_id(userTmp);
    qDebug() << "User Tmp: " << userTmp->id << userTmp->name << userTmp->age;

#if _QX_SERIALIZE_XML
    // 将容器中的用户导出到 XML 文件中(序列化)
    qx::serialization::xml::to_file(users, "./export_users.xml");

    // 将 XML 中的用户导入至新容器
    VectorUser usersXmlTmp;
    qx::serialization::xml::from_file(usersXmlTmp, "./export_users.xml");
#endif

#ifndef _QX_NO_JSON
    // 将容器中的用户导出到 Json 文件中(序列化)
    qx::serialization::json::to_file(users, "./export_users.json");

    // 将 Json 文件中的用户导入至新容器
    VectorUser usersJsonTmp;
    qx::serialization::json::from_file(usersJsonTmp, "./export_users.json");
#endif

    // 克隆一个用户
    UserPtr uClone = qx::clone_to_qt_shared_ptr(*u1);
    qDebug() << "Clone from u1: " << uClone->id << uClone->name << uClone->age;

    // 按类名(factory)创建新用户
    qx::any uAny = qx::create("User");

    // 将用户插入到 qx::cache
    qx::cache::set("users", users);

    // 从 qx::cache 中删除所有元素
    qx::cache::clear();

    // 内存泄漏
    User *user = new User();

    return a.exec();

Aqui nos concentramos em QxOrm_Impl.h, que é usado para detectar vazamentos de memória. Ele deve ser incluído em todos os *.cpp se estiver usando o módulo QxMemLeak ou o mecanismo boost::serialization, caso contrário, é opcional (não obrigatório).

execute o programa

A execução do programa não apenas imprimirá uma série de informações de saída, mas também gerará arquivos de banco de dados correspondentes e arquivos JSON.

O QxOrm não oculta as consultas SQL (por padrão, todas as instruções são exibidas), portanto, o processo de execução pode ser visto no console.

[QxOrm] qx::QxSqlDatabase : create new database connection in thread '0x2554' with key '{652e45d3-7186-4bd6-81d1-9ff32fcff744}'
[QxOrm] sql query (total: 31.8 ms, db_exec: 0 ms) : CREATE TABLE User (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)
[QxOrm] sql query (total: 12 ms, db_exec: 1.91 ms) : INSERT INTO User (name, age) VALUES (:name, :age)
[QxOrm] sql query (total: 9.35 ms, db_exec: 0.511 ms) : UPDATE User SET id = :id, name = :name, age = :age WHERE id = :id_bis
[QxOrm] sql query (total: 8.49 ms, db_exec: 8.43 ms) : DELETE FROM User WHERE id = :id
[QxOrm] sql query (total: 0.125 ms, db_exec: 0.0994 ms) : SELECT COUNT(*) FROM User
User Count:  2
[QxOrm] sql query (total: 0.153 ms, db_exec: 0.068 ms) : SELECT User.id AS User_id_0, User.name AS User_name_0, User.age AS User_age_0 FROM User WHERE User.id = :id
User Tmp:  3 "Rose" 18
Clone from u1:  1 "Jack Ma" 30

Se você deseja visualizar as informações do banco de dados Users.db, pode usar uma ferramenta de visualização de banco de dados (por exemplo: Navicat Premium).

O arquivo JSON é gerado por serialização, abra export_users.json e você verá os dados correspondentes.

[
    {
    
    
        "age": 30,
        "id": 1,
        "name": "Jack Ma"
    },
    {
    
    
        "age": 38,
        "id": 2,
        "name": "Pony modified"
    },
    {
    
    
        "age": 18,
        "id": 3,
        "name": "Rose"
    }
]

referência

O site QxOrm fornece um manual do usuário.

O objetivo deste documento é fornecer um guia do usuário para aprender como usar as funções da biblioteca QxOrm. Este manual destina-se a desenvolvedores e arquitetos de software que procuram uma solução para gerenciar camadas de dados persistentes em C++/Qt. Para entender este documento, são necessárias habilidades técnicas em C++ e bancos de dados.

NOTA: Todas as funções descritas neste manual/guia do usuário podem ser definidas de forma rápida e fácil usando o aplicativo QxEntityEditor (editor gráfico, designer de modelo de dados e gerador de código-fonte para a biblioteca QxOrm). Outro documento dedicado ao aplicativo QxEntityEditor está disponível no site do QxOrm.

Ferramenta de gerenciamento de modelo de dados

QxEntityEditor é um editor gráfico para a biblioteca QxOrm: QxEntityEditor fornece uma abordagem gráfica para gerenciar modelos de dados. O QxEntityEditor é multiplataforma (para Windows, Linux e Mac OS X) e gera código nativo para todos os ambientes: desktop (Windows, Linux, Mac OS X), embarcado e móvel (Android, iOS, Windows Phone, Raspberry Pi, etc. )). O manual do usuário (documentação) do aplicativo QxEntityEditor está disponível no site da QxOrm.

O QxEntityEditor é baseado em plug-ins e fornece várias maneiras de importar/exportar modelos de dados:

  • Gera automaticamente classes persistentes C++ (cadastradas no contexto QxOrm);
  • Gere automaticamente scripts DDL SQL (esquemas de banco de dados) para SQLite, MySQL, PostgreSQL, Oracle e MS SQL Server;
  • Gerenciar a evolução do esquema para cada versão do projeto (ALTER TABLE, ADD COLUMN, DROP INDEX, etc.);
  • Use o módulo QxService para transferir modelos de dados pela rede e criar rapidamente aplicativos cliente/servidor;
  • Importar estruturas de banco de dados existentes (usando conexões ODBC ou drivers nativos) para bancos de dados SQLite, MySQL, PostgreSQL, Oracle e MS SQL Server;
  • Como cada projeto é diferente, o QxEntityEditor fornece várias maneiras de personalizar os arquivos gerados (especialmente o mecanismo javascript e o depurador integrado).

conclusão

Como o QxOrm pode mapear automaticamente as propriedades e campos entre o objeto Entidade e a Tabela no banco de dados, quase não há necessidade de escrever o código da camada de acesso a dados em projetos reais, o que melhora muito nossa eficiência de desenvolvimento.

Mas QxOrm não pode resolver todos os problemas de SQL e banco de dados (nenhuma ferramenta é onipotente), então às vezes você precisa usar o mecanismo QtSql do Qt para escrever sua própria consulta SQL ou procedimento armazenado.

おすすめ

転載: blog.csdn.net/pointerz_zyz/article/details/129699446
01-