Hello,
Yes QxOrm library supports inheritance, you can define some properties (so database columns) in a base class, and all derived classes will have same columns (+ specific columns defined in each derived classes).
The restriction is about relationships : you must define your relationships in the derived classes (you can't define them in a base class), because relationships must know target entity/table at compile time.
I strongly recommend to use QxEntityEditor application to know how to define something : with QxEntityEditor, you cannot be wrong : the generated C++ source code will be OK to use with QxOrm library.
You can use it free of charge with a limitation of 5 entities per project : so this is OK to know how to manage inheritance for example.
Here is an example I use to develop QxEntityEditor application. It is very similar to
qx::QxPersistable class you can find in the documentation here :
- documentation :
https://www.qxorm.com/qxorm_en/manual.html#manual_450-
*.hpp :
https://www.qxorm.com/qxorm_en/resource ... e_hpp.html-
*.cpp :
https://www.qxorm.com/qxorm_en/resource ... e_cpp.htmlSo in QxEntityEditor application, all my model classes inherit from
model::persistable base class (and abstract class), where some properties/columns are defined (like
m_dtDateCreation,
m_dtDateModification,
m_lUserIdCreation, etc...), and some callbacks are also defined to manage triggers (
OnBeforeInsert,
OnAfterUpdate, etc...).
Then as an example, I will provide the
model::comment table which inherit from
model::persistable and add some properties/columns like
m_sTitle,
m_sText, etc...
Here are the classes :
* persistable.h :
- Code: Select all
#ifndef _MODEL_PERSISTABLE_H_
#define _MODEL_PERSISTABLE_H_
#ifdef _MSC_VER
#pragma once
#endif
#ifdef _QX_NO_PRECOMPILED_HEADER
#ifndef Q_MOC_RUN
#include <precompiled_qxee.h> // Need to include precompiled header for the generated moc file
#endif // Q_MOC_RUN
#endif // _QX_NO_PRECOMPILED_HEADER
namespace model {
class persistable;
} // namespace model
namespace qx {
namespace dao {
namespace detail {
template <>
struct QxDao_Trigger<model::persistable>;
} // namespace detail
} // namespace dao
} // namespace qx
namespace model {
/*!
* \brief model::persistable : super base class for persistent classes with many features and methods to override (be careful, don't forget to use QX_PERSISTABLE_HPP() and QX_PERSISTABLE_CPP() macros for each derived class)
*/
class QX_ENTITY_EDITOR_EXPORT persistable : public QObject, public qx::IxPersistable
{
Q_OBJECT
QX_REGISTER_FRIEND_CLASS(model::persistable)
friend struct qx::dao::detail::QxDao_Trigger<model::persistable>;
public:
typedef QHash<QString, QVariant> type_meta_data;
typedef std::shared_ptr<type_meta_data> type_meta_data_ptr;
protected:
long m_lId; //!< Id of current instance stored into database
qx::QxDateTimeNeutral m_dtDateCreation; //!< Creation date-time automatically calculated before INSERT query
qx::QxDateTimeNeutral m_dtDateModification; //!< Modification date-time automatically calculated before INSERT and UPDATE queries
qx::QxDateTimeNeutral m_dtDateFetched; //!< Can be used for optimization : check date/time fetched and date/time modification before refetch
long m_lUserIdCreation; //!< Creation user id during INSERT query
long m_lUserIdModification; //!< Modification user id during INSERT and UPDATE queries
type_meta_data_ptr m_pListOfMetaData; //!< List of meta-data associated to current instance
long m_lAppVersion; //!< Current application version when instance is stored into database
static bool m_bDisableTriggers; //!< Disable all triggers (fetch, insert, update, delete) : can be useful for an import process for example
static bool m_bDisableValidation; //!< Disable validation engine : can be useful for an import process for example
public:
persistable();
persistable(long id);
virtual ~persistable() = 0;
virtual void init();
virtual void terminate();
long getId() const;
QDateTime getDateCreation() const;
QDateTime getDateModification() const;
QDateTime getDateFetched() const;
long getUserIdCreation() const;
long getUserIdModification() const;
type_meta_data_ptr getAllMetaData() const;
long getAppVersion() const;
void setId(long l);
void setDateCreation(const QDateTime & dt);
void setDateModification(const QDateTime & dt);
void setUserIdCreation(long l);
void setUserIdModification(long l);
void setMetaData(const QString & key, const QVariant & value);
QVariant getMetaData(const QString & key) const;
void removeMetaData(const QString & key);
QList<QString> getAllMetaDataKeys() const;
long countMetaData() const;
void clearMetaData();
bool operator==(const model::persistable & other) const;
static void setDisableTriggers(bool b);
static void setDisableValidation(bool b);
private:
void initMetaData();
protected:
// -- List of useful protected methods to override into derived class -- //
virtual void qxIsValid(qx::QxInvalidValueX & invalidValues);
virtual void qxOnBeforeInsert(qx::dao::detail::IxDao_Helper * dao);
virtual void qxOnBeforeUpdate(qx::dao::detail::IxDao_Helper * dao);
virtual void qxOnBeforeDelete(qx::dao::detail::IxDao_Helper * dao);
virtual void qxOnBeforeFetch(qx::dao::detail::IxDao_Helper * dao);
virtual void qxOnAfterInsert(qx::dao::detail::IxDao_Helper * dao);
virtual void qxOnAfterUpdate(qx::dao::detail::IxDao_Helper * dao);
virtual void qxOnAfterDelete(qx::dao::detail::IxDao_Helper * dao);
virtual void qxOnAfterFetch(qx::dao::detail::IxDao_Helper * dao);
private:
void qxIsValidInternal(qx::QxInvalidValueX & invalidValues);
Q_SIGNALS:
void qxOnBeforeInsert(model::persistable * p);
void qxOnBeforeUpdate(model::persistable * p);
void qxOnBeforeDelete(model::persistable * p);
void qxOnBeforeFetch(model::persistable * p);
void qxOnAfterInsert(model::persistable * p);
void qxOnAfterUpdate(model::persistable * p);
void qxOnAfterDelete(model::persistable * p);
void qxOnAfterFetch(model::persistable * p);
public:
// -- List of useful public methods available from 'qx::IxPersistable' interface (using QX_PERSISTABLE_HPP() and QX_PERSISTABLE_CPP() macros) -- //
/*
virtual long qxCount(const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxFetchById(const QVariant & id = QVariant(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxFetchAll(qx::IxPersistableCollection * list = NULL, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery & query, qx::IxPersistableCollection * list = NULL, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxDeleteById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxDestroyById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL);
virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
virtual qx_bool qxExist(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList());
virtual qx::IxPersistableCollection_ptr qxNewPersistableCollection() const;
virtual qx::IxClass * qxClass() const;
*/
};
typedef std::shared_ptr<model::persistable> persistable_ptr;
} // namespace model
QX_REGISTER_ABSTRACT_CLASS(model::persistable)
QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_ENTITY_EDITOR(model::persistable, QObject, 0, model_persistable)
Q_DECLARE_METATYPE(model::persistable_ptr)
namespace qx {
namespace dao {
namespace detail {
template <>
struct QxDao_Trigger<model::persistable>
{
static inline void onBeforeInsert(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnBeforeInsert(dao); } }
static inline void onBeforeUpdate(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnBeforeUpdate(dao); } }
static inline void onBeforeDelete(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnBeforeDelete(dao); } }
static inline void onBeforeFetch(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnBeforeFetch(dao); } }
static inline void onAfterInsert(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnAfterInsert(dao); } }
static inline void onAfterUpdate(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnAfterUpdate(dao); } }
static inline void onAfterDelete(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnAfterDelete(dao); } }
static inline void onAfterFetch(model::persistable * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->qxOnAfterFetch(dao); } }
};
} // namespace detail
} // namespace dao
} // namespace qx
#endif // _MODEL_PERSISTABLE_H_
* persistable.cpp :
- Code: Select all
#include <precompiled_qxee.h>
#include <model/persistable.h>
#include <QxOrm_Impl.h>
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_ENTITY_EDITOR(model::persistable, model_persistable)
namespace qx {
template <>
void register_class(QxClass<model::persistable> & t)
{
qx::IxDataMember * pData = NULL;
t.setPropertyBag("QX_DO_NOT_CREATE_TABLE", "1");
t.id(& model::persistable::m_lId, "id");
pData = t.data(& model::persistable::m_dtDateCreation, "dt_creation");
pData = t.data(& model::persistable::m_dtDateModification, "dt_modification");
pData = t.data(& model::persistable::m_lUserIdCreation, "user_id_creation");
pData = t.data(& model::persistable::m_lUserIdModification, "user_id_modification");
pData = t.data(& model::persistable::m_lAppVersion, "app_version");
pData = t.data(& model::persistable::m_pListOfMetaData, "list_meta_data");
pData->setSqlType("TEXT");
QxValidatorX<model::persistable> * pAllValidator = t.getAllValidator();
pAllValidator->add_CustomValidator(std::mem_fn(& model::persistable::qxIsValidInternal));
}
} // namespace qx
namespace model {
bool persistable::m_bDisableTriggers = false;
bool persistable::m_bDisableValidation = false;
persistable::persistable() : QObject(), qx::IxPersistable(), m_lId(0), m_lUserIdCreation(0), m_lUserIdModification(0), m_lAppVersion(0) { ; }
persistable::persistable(long id) : QObject(), qx::IxPersistable(), m_lId(id), m_lUserIdCreation(0), m_lUserIdModification(0), m_lAppVersion(0) { ; }
persistable::~persistable() { ; }
void persistable::init() { ; }
void persistable::terminate() { ; }
long persistable::getId() const { return m_lId; }
QDateTime persistable::getDateCreation() const { return m_dtDateCreation.toDateTime(); }
QDateTime persistable::getDateModification() const { return m_dtDateModification.toDateTime(); }
QDateTime persistable::getDateFetched() const { return m_dtDateFetched.toDateTime(); }
long persistable::getUserIdCreation() const { return m_lUserIdCreation; }
long persistable::getUserIdModification() const { return m_lUserIdModification; }
persistable::type_meta_data_ptr persistable::getAllMetaData() const { return m_pListOfMetaData; }
long persistable::getAppVersion() const { return m_lAppVersion; }
void persistable::setId(long l) { m_lId = l; }
void persistable::setDateCreation(const QDateTime & dt) { m_dtDateCreation.setDateTime(dt); }
void persistable::setDateModification(const QDateTime & dt) { m_dtDateModification.setDateTime(dt); }
void persistable::setUserIdCreation(long l) { m_lUserIdCreation = l; }
void persistable::setUserIdModification(long l) { m_lUserIdModification = l; }
void persistable::setDisableTriggers(bool b) { m_bDisableTriggers = b; }
void persistable::setDisableValidation(bool b) { m_bDisableValidation = b; }
void persistable::setMetaData(const QString & key, const QVariant & value) { initMetaData(); m_pListOfMetaData->insert(key, value); }
QVariant persistable::getMetaData(const QString & key) const { return ((m_pListOfMetaData && m_pListOfMetaData->contains(key)) ? m_pListOfMetaData->value(key) : QVariant()); }
void persistable::removeMetaData(const QString & key) { if (m_pListOfMetaData) { m_pListOfMetaData->remove(key); } }
QList<QString> persistable::getAllMetaDataKeys() const { return (m_pListOfMetaData ? m_pListOfMetaData->keys() : QList<QString>()); }
long persistable::countMetaData() const { return (m_pListOfMetaData ? m_pListOfMetaData->count() : 0); }
void persistable::clearMetaData() { m_pListOfMetaData.reset(); }
void persistable::initMetaData() { if (! m_pListOfMetaData) { m_pListOfMetaData = std::shared_ptr< QHash<QString, QVariant> >(new QHash<QString, QVariant>()); } }
void persistable::qxIsValidInternal(qx::QxInvalidValueX & invalidValues) { this->qxIsValid(invalidValues); }
void persistable::qxIsValid(qx::QxInvalidValueX & invalidValues) { Q_UNUSED(invalidValues); }
void persistable::qxOnBeforeInsert(qx::dao::detail::IxDao_Helper * dao)
{
Q_UNUSED(dao);
if (m_bDisableTriggers) { return; }
m_dtDateCreation.setDateTime(QDateTime::currentDateTime());
m_dtDateModification = m_dtDateCreation;
Q_EMIT qxOnBeforeInsert(this);
}
void persistable::qxOnBeforeUpdate(qx::dao::detail::IxDao_Helper * dao)
{
Q_UNUSED(dao);
if (m_bDisableTriggers) { return; }
m_dtDateModification.setDateTime(QDateTime::currentDateTime());
Q_EMIT qxOnBeforeUpdate(this);
}
void persistable::qxOnBeforeDelete(qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(dao); if (! m_bDisableTriggers) { Q_EMIT qxOnBeforeDelete(this); } }
void persistable::qxOnBeforeFetch(qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(dao); if (! m_bDisableTriggers) { Q_EMIT qxOnBeforeFetch(this); } }
void persistable::qxOnAfterInsert(qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(dao); if (! m_bDisableTriggers) { Q_EMIT qxOnAfterInsert(this); } }
void persistable::qxOnAfterUpdate(qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(dao); if (! m_bDisableTriggers) { Q_EMIT qxOnAfterUpdate(this); } }
void persistable::qxOnAfterDelete(qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(dao); if (! m_bDisableTriggers) { Q_EMIT qxOnAfterDelete(this); } }
void persistable::qxOnAfterFetch(qx::dao::detail::IxDao_Helper * dao)
{
Q_UNUSED(dao);
if (m_bDisableTriggers) { return; }
m_dtDateFetched.setDateTime(QDateTime::currentDateTime());
Q_EMIT qxOnAfterFetch(this);
}
bool persistable::operator==(const model::persistable & other) const
{
if (this == (& other)) { return true; }
bool bEqual = (m_lId == other.m_lId);
bEqual = (bEqual && (m_dtDateCreation.toNeutral() == other.m_dtDateCreation.toNeutral()));
bEqual = (bEqual && (m_dtDateModification.toNeutral() == other.m_dtDateModification.toNeutral()));
bEqual = (bEqual && (m_lUserIdCreation == other.m_lUserIdCreation));
bEqual = (bEqual && (m_lUserIdModification == other.m_lUserIdModification));
bEqual = (bEqual && (m_lAppVersion == other.m_lAppVersion));
if (bEqual && m_pListOfMetaData && ! other.m_pListOfMetaData) { bEqual = false; }
else if (bEqual && ! m_pListOfMetaData && other.m_pListOfMetaData) { bEqual = false; }
else if (bEqual && m_pListOfMetaData && other.m_pListOfMetaData)
{ bEqual = (bEqual && ((* m_pListOfMetaData) == (* other.m_pListOfMetaData))); }
return bEqual;
}
} // namespace model
* comment.h :
- Code: Select all
#ifndef _MODEL_COMMENT_H_
#define _MODEL_COMMENT_H_
#ifdef _MSC_VER
#pragma once
#endif
#ifdef _QX_NO_PRECOMPILED_HEADER
#ifndef Q_MOC_RUN
#include <precompiled_qxee.h> // Need to include precompiled header for the generated moc file
#endif // Q_MOC_RUN
#endif // _QX_NO_PRECOMPILED_HEADER
#include <model/persistable.h>
#ifndef _QX_NO_JSON
#include <tools/json_qx_collection.h>
#endif // _QX_NO_JSON
namespace model {
/*!
* \brief model::comment : TODO...
*/
class QX_ENTITY_EDITOR_EXPORT comment : public model::persistable, public std::enable_shared_from_this<model::comment>
{
Q_OBJECT
QX_REGISTER_FRIEND_CLASS(model::comment)
QX_PERSISTABLE_HPP(model::comment)
protected:
QString m_sTitle; //!< Comment title
QString m_sText; //!< Comment text
bool m_bTextHtml; //!< Comment text in HTML format
public:
comment();
comment(long id);
virtual ~comment();
virtual void terminate();
std::shared_ptr<model::comment> getThis();
QString getTitle() const;
QString getText() const;
bool getTextHtml() const;
void setTitle(const QString & s);
void setText(const QString & s);
void setTextHtml(bool b);
bool operator==(const model::comment & other) const;
protected:
virtual void qxIsValid(qx::QxInvalidValueX & invalidValues);
};
typedef std::shared_ptr<comment> comment_ptr;
typedef qx::QxCollection<long, comment_ptr> list_of_comment;
typedef std::shared_ptr<list_of_comment> list_of_comment_ptr;
} // namespace model
QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_ENTITY_EDITOR(model::comment, model::persistable, 0, model_comment)
Q_DECLARE_METATYPE(model::comment_ptr)
#ifndef _QX_NO_JSON
namespace qx {
namespace cvt {
namespace detail {
template <>
struct QxConvert_ToJson< model::list_of_comment >
{
static inline QJsonValue toJson(const model::list_of_comment & t, const QString & format)
{ return tools::json_qx_collection<long, model::comment_ptr>::toJsonAsList(t, format); }
};
template <>
struct QxConvert_FromJson< model::list_of_comment >
{
static inline qx_bool fromJson(const QJsonValue & j, model::list_of_comment & t, const QString & format)
{ return tools::json_qx_collection<long, model::comment_ptr>::fromJsonAsList(j, t, format); }
};
} // namespace detail
} // namespace cvt
} // namespace qx
#endif // _QX_NO_JSON
#endif // _MODEL_COMMENT_H_
* comment.cpp :
- Code: Select all
#include <precompiled_qxee.h>
#include <model/comment.h>
#include <QxOrm_Impl.h>
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_ENTITY_EDITOR(model::comment, model_comment)
namespace qx {
template <>
void register_class(QxClass<model::comment> & t)
{
qx::IxDataMember * pData = NULL; Q_UNUSED(pData);
t.setName("t_comment");
pData = t.data(& model::comment::m_sTitle, "comment_title");
pData = t.data(& model::comment::m_sText, "comment_text");
pData = t.data(& model::comment::m_bTextHtml, "comment_text_html");
}
} // namespace qx
namespace model {
QX_PERSISTABLE_CPP(comment)
comment::comment() : model::persistable(), m_bTextHtml(false) { ; }
comment::comment(long id) : model::persistable(id), m_bTextHtml(false) { ; }
comment::~comment() { ; }
comment_ptr comment::getThis() { try { return shared_from_this(); } catch(...) { return comment_ptr(); } }
void comment::terminate() { persistable::terminate(); }
QString comment::getTitle() const { return m_sTitle; }
QString comment::getText() const { return m_sText; }
bool comment::getTextHtml() const { return m_bTextHtml; }
void comment::setTitle(const QString & s) { m_sTitle = s; }
void comment::setText(const QString & s) { m_sText = s; }
void comment::setTextHtml(bool b) { m_bTextHtml = b; }
void comment::qxIsValid(qx::QxInvalidValueX & invalidValues)
{
model::persistable::qxIsValid(invalidValues);
if (model::persistable::m_bDisableValidation) { return; }
// Check comment title
m_sTitle = m_sTitle.trimmed();
if (m_sTitle.isEmpty()) { invalidValues.insert("Comment title cannot be empty"); }
}
bool comment::operator==(const model::comment & other) const
{
if (this == (& other)) { return true; }
bool bEqual = persistable::operator ==(other);
bEqual = (bEqual && (m_sTitle == other.m_sTitle));
bEqual = (bEqual && (m_sText == other.m_sText));
bEqual = (bEqual && (m_bTextHtml == other.m_bTextHtml));
return bEqual;
}
} // namespace model