Files
XdlOrm/include/QxDao/QxSession.h
2026-04-03 11:32:07 +08:00

458 lines
15 KiB
C++

/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 XDL Team (ic-east.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and XDL Team
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** ic-east.com
**
****************************************************************************/
#ifndef _QX_DAO_SESSION_H_
#define _QX_DAO_SESSION_H_
#ifdef _MSC_VER
#pragma once
#endif
/*!
* \file QxSession.h
* \author XDL Team
* \ingroup QxDao
* \brief Define a session to manage automatically database transactions (using C++ RAII)
*/
#include <QtSql/qsqldatabase.h>
#include <QtSql/qsqlquery.h>
#include <QtSql/qsqlerror.h>
#include <QtSql/qsqldriver.h>
#include <QtCore/qlist.h>
#include <QxCommon/QxBool.h>
#include <QxDao/QxDao.h>
#include <QxDao/QxSqlQuery.h>
#include <QxDao/QxSqlError.h>
#include <QxRegister/QxClass.h>
namespace qx
{
/*!
* \ingroup QxDao
* \brief qx::QxSession : define a session to manage automatically database transactions (using C++ RAII)
*
* A database <b>transaction</b> is a sequence of operations performed as a single logical unit of work.
* If no errors occurred during the execution of the transaction then the system <b>commits</b> the transaction.
* If an error occurs during the transaction, or if the user specifies a <b>rollback</b> operation, the data manipulations within the transaction are not persisted to the database.
*
* The <i>qx::QxSession</i> class of QxOrm library is designed to manage automatically database transactions (using <i>C++ RAII</i>) :
* \code
{ // Start a scope where a new session is instantiated
// Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened
qx::QxSession session;
// Execute some operations with database (using += operator of qx::QxSession class and session database connexion)
session += qx::dao::insert(my_object, session.database());
session += qx::dao::update(my_object, session.database());
session += qx::dao::fetch_by_id(my_object, session.database());
session += qx::dao::delete_by_id(my_object, session.database());
// If the session is not valid (so an error occured) => display first error
if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
} // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error)
* \endcode
*
* <i>Note :</i> a session can throw a <i>qx::dao::sql_error</i> exception when a SQL error occured (by default, there is no exception).
* You can setup this feature using :
* - <i>qx::QxSession</i> constructor (for a specific session) ;
* - <i>qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b)</i> parameter (for all sessions).
*
* <i>Other note :</i> don't forget to pass the session database connexion to each <i>qx::dao::xxx</i> functions (using <i>session.database()</i> method).
* Moreover, you can manage your own database connexion (from a connexion pool for example) using constructor of <i>qx::QxSession</i> class.
*
* <i>qx::QxSession</i> class provides also persistent methods (CRUD) to make easier to write C++ code.
* Here is the same example using methods of <i>qx::QxSession</i> class instead of functions into namespace <i>qx::dao</i> :
* \code
{ // Start a scope where a new session is instantiated
// Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened
qx::QxSession session;
// Execute some operations with database
session.insert(my_object);
session.update(my_object);
session.fetchById(my_object);
session.deleteById(my_object);
// If the session is not valid (so an error occured) => display first error
if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
} // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error)
* \endcode
*/
class QX_DLL_EXPORT QxSession
{
private:
struct QxSessionImpl;
std::shared_ptr<QxSessionImpl> m_pImpl; //!< Private implementation idiom (use std::shared_ptr instead of std::unique_ptr because of incomplete type)
public:
QxSession();
QxSession(const QSqlDatabase &database);
QxSession(const QSqlDatabase &database, bool bOpenTransaction);
QxSession(const QSqlDatabase &database, bool bOpenTransaction, bool bThrowable, bool bAutoRollbackWhenDestroyed = false);
virtual ~QxSession();
bool isThrowable() const;
bool isOpened() const;
bool isValid() const;
bool isAutoRollbackWhenDestroyed() const;
void setAutoRollbackWhenDestroyed(bool b);
QSqlError firstError() const;
QSqlError lastError() const;
QList<QSqlError> allErrors() const;
const QSqlDatabase *database() const;
QSqlDatabase *database();
bool open();
bool close();
bool commit();
bool rollback();
QxSession &operator+=(const QSqlError &err);
static QxSession *getActiveSession(QSqlDatabase *db);
void ignoreSoftDelete(bool bIgnoreSoftDelete = true, const QStringList &classesToIgnore = QStringList());
bool checkIgnoreSoftDelete(const QString &classKey) const;
QString getIgnoreSoftDeleteHash() const;
template <class T>
long count(const qx::QxSqlQuery &query = qx::QxSqlQuery())
{
return qx::dao::count<T>(query, this->database());
}
template <class T>
QSqlError count(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery())
{
return qx::dao::count<T>(lCount, query, this->database());
}
template <class T>
T *fetchById(const QVariant &id, const QStringList &columns = QStringList(), const QStringList &relation = QStringList())
{
IxDataMemberX *pDataMemberX = QxClass<T>::getSingleton()->getDataMemberX();
IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL);
if (!pDataMemberId)
{
qAssert(false);
return NULL;
}
T *t = new T();
QSqlError err;
pDataMemberId->fromVariant(t, id, -1, qx::cvt::context::e_database);
if (relation.count() == 0)
{
err = qx::dao::fetch_by_id((*t), this->database(), columns);
}
else
{
err = qx::dao::fetch_by_id_with_relation(relation, (*t), this->database());
}
if (err.isValid())
{
delete t;
t = NULL;
(*this) += err;
}
return t;
}
template <class T>
QSqlError fetchById(T &t, const QStringList &columns = QStringList(), const QStringList &relation = QStringList())
{
QSqlError err;
if (relation.count() == 0)
{
err = qx::dao::fetch_by_id(t, this->database(), columns);
}
else
{
err = qx::dao::fetch_by_id_with_relation(relation, t, this->database());
}
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError fetchAll(T &t, const QStringList &columns = QStringList(), const QStringList &relation = QStringList())
{
QSqlError err;
if (relation.count() == 0)
{
err = qx::dao::fetch_all(t, this->database(), columns);
}
else
{
err = qx::dao::fetch_all_with_relation(relation, t, this->database());
}
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError fetchByQuery(const qx::QxSqlQuery &query, T &t, const QStringList &columns = QStringList(), const QStringList &relation = QStringList())
{
QSqlError err;
if (relation.count() == 0)
{
err = qx::dao::fetch_by_query(query, t, this->database(), columns);
}
else
{
err = qx::dao::fetch_by_query_with_relation(relation, query, t, this->database());
}
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError insert(T &t, const QStringList &relation = QStringList(), bool bUseExecBatch = false)
{
QSqlError err;
if (relation.count() == 0)
{
err = qx::dao::insert(t, this->database(), bUseExecBatch);
}
else
{
err = qx::dao::insert_with_relation(relation, t, this->database());
}
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError update(T &t, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), bool bUseExecBatch = false)
{
QSqlError err;
if (relation.count() == 0)
{
err = qx::dao::update_by_query(query, t, this->database(), columns, bUseExecBatch);
}
else
{
err = qx::dao::update_by_query_with_relation(relation, query, t, this->database());
}
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError save(T &t, const QStringList &relation = QStringList())
{
QSqlError err;
if (relation.count() == 0)
{
err = qx::dao::save(t, this->database());
}
else
{
err = qx::dao::save_with_relation(relation, t, this->database());
}
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError deleteById(const QVariant &id)
{
IxDataMemberX *pDataMemberX = QxClass<T>::getSingleton()->getDataMemberX();
IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL);
if (!pDataMemberId)
{
qAssert(false);
return QSqlError();
}
std::shared_ptr<T> t = std::make_shared<T>();
pDataMemberId->fromVariant(t.get(), id, -1, qx::cvt::context::e_database);
QSqlError err = qx::dao::delete_by_id((*t), this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError deleteById(T &t, bool bUseExecBatch = false)
{
QSqlError err = qx::dao::delete_by_id(t, this->database(), bUseExecBatch);
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError deleteAll()
{
QSqlError err = qx::dao::delete_all<T>(this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError deleteByQuery(const qx::QxSqlQuery &query)
{
QSqlError err = qx::dao::delete_by_query<T>(query, this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError destroyById(const QVariant &id)
{
IxDataMemberX *pDataMemberX = QxClass<T>::getSingleton()->getDataMemberX();
IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL);
if (!pDataMemberId)
{
qAssert(false);
return QSqlError();
}
std::shared_ptr<T> t = std::make_shared<T>();
pDataMemberId->fromVariant(t.get(), id, -1, qx::cvt::context::e_database);
QSqlError err = qx::dao::destroy_by_id((*t), this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError destroyById(T &t, bool bUseExecBatch = false)
{
QSqlError err = qx::dao::destroy_by_id(t, this->database(), bUseExecBatch);
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError destroyAll()
{
QSqlError err = qx::dao::destroy_all<T>(this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError destroyByQuery(const qx::QxSqlQuery &query)
{
QSqlError err = qx::dao::destroy_by_query<T>(query, this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
QSqlError executeQuery(qx::QxSqlQuery &query, T &t)
{
QSqlError err = qx::dao::execute_query<T>(query, t, this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
QSqlError callQuery(qx::QxSqlQuery &query)
{
QSqlError err = qx::dao::call_query(query, this->database());
if (err.isValid())
{
(*this) += err;
}
return err;
}
template <class T>
qx_bool exist(T &t)
{
return qx::dao::exist(t, this->database());
}
private:
QxSession(const QxSession &other) { Q_UNUSED(other); }
QxSession &operator=(const QxSession &other)
{
Q_UNUSED(other);
return (*this);
}
};
} // namespace qx
#endif // _QX_DAO_SESSION_H_