458 lines
15 KiB
C++
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_
|