Inheritance

Forum for posting problems using QxOrm library

Inheritance

Postby asoletti » Sat Dec 07, 2019 9:04 am

Hi, Im new to QxOrm so I've been digging a couple days through source and tests to understand how it works.

I've been trying to create some kinda of super class based on tests/qxDllSample/Dll1 example but Iv been stuck on compile errors.

I noticed that the class CPerson does not inherit from QxPersistable class on this *test*. When I change the inherit I get a compiler error regarding an already defined register_class template.

What I would like to do is:

Consider I have the following classes.

Base (abstract, not persistable)
Person (persistable, inherists from Base)

I would like to put some methods on it, and also add a few persistable fields (using register_class template) which will be added to derivated classes like, createdBy, updatedBy fields.
In the Person class, I add all the fields (and another register_class template).

Is it possible? Or this kinda of inheritance is not correct to do it? Should I duplicate code and write all persistable fields in the final class (I'll prolly have a lot of duplicate code) ?

Regards,
asoletti
 
Posts: 3
Joined: Sat Dec 07, 2019 8:44 am

Re: Inheritance

Postby qxorm » Sun Dec 08, 2019 8:40 am

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.html

So 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
qxorm
Site Admin
 
Posts: 481
Joined: Mon Apr 12, 2010 7:45 am


Return to QxOrm - Help

Who is online

Users browsing this forum: No registered users and 3 guests

cron