QxOrm可以持久化指向抽象类的指针
Can QxOrm persist pointers to abstract classes?
我正试图弄清楚如何使用QxOrm来持久化一个大型复杂的类结构。我已经取得了一些进展,但我一直纠结于如何处理指向抽象类的指针。
这里有一个简单的例子,其中Table(一个具体类)有一个指向某种Shape(一个抽象类)的指针:
class Table {
Shape* top;
};
class Shape {
public:
virtual float getWidth() = 0;
};
class Square : public Shape {
virtual float getWidth();
};
class Circle : public Shape {
virtual float getWidth();
};
当我尝试这个时,我收到错误消息,抱怨Shape是抽象的。
在我看来,QxOrm不可能做到这一点,我怀疑,因为它唯一的继承模型是Concrete。
有人知道这是否可能吗?我宁愿不放弃QxOrm,因为它在很多方面看起来都很好(我已经花了很多时间),但看起来我必须这样做。
Update1:我知道QX_REGISTER_ABSTRACT_CLASS
。它对这个用例没有帮助。
Update2:我尝试将qxBlog示例中的comment
类抽象化。我将其作为qx::IxPersistable
的子类,并使用了QX_REGISTER_ABSTRACT_CLASS
宏。当我编译时,它在调用宏QX_PERSISTABLE_CPP
时死亡,带有:
../..//QxOrm/include/QxDao/..//inl/QxDao/QxDao_Count.inl:36:错误:无法将变量"t"声明为抽象类型"comment"
其他地方也有类似的错误消息。
(顺便说一句,我本来打算先在QxOrm论坛上提问,但当时没有。)
谢谢!
要将抽象类注册到QxOrm上下文中:http://www.qxorm.com/qxorm_en/faq.html#faq_140
为了使用指向基类的指针,我认为qx::IxPersistable接口可以帮助您:http://www.qxorm.com/qxorm_en/faq.html#faq_260
注意:QxOrm论坛现已开放。。。
这是一个使用qx::IxPersistable接口和QxOrm触发器的通用解决方案。这个想法是存储基类的ID+与ID相关的类型:这样,您将能够实例化所有派生类。
---MyBaseClass.h文件:
class QX_DLL2_EXPORT MyBaseClass : public qx::IxPersistable
{
public:
long id;
MyBaseClass() : qx::IxPersistable(), id(0) { ; }
virtual ~MyBaseClass() = 0;
};
QX_REGISTER_ABSTRACT_CLASS(MyBaseClass)
QX_REGISTER_HPP_QX_DLL2(MyBaseClass, qx::trait::no_base_class_defined, 0)
typedef boost::shared_ptr<MyBaseClass> MyBaseClass_ptr;
---MyDerivedClass1.h文件:
class QX_DLL2_EXPORT MyDerivedClass1 : public MyBaseClass
{
QX_PERSISTABLE_HPP(MyDerivedClass1)
public:
QString description;
MyDerivedClass1() : MyBaseClass() { ; }
virtual ~MyDerivedClass1() { ; }
};
QX_REGISTER_HPP_QX_DLL2(MyDerivedClass1, MyBaseClass, 0)
typedef boost::shared_ptr<MyDerivedClass1> MyDerivedClass1_ptr;
---MyDerivedClass2.h文件:
class QX_DLL2_EXPORT MyDerivedClass2 : public MyBaseClass
{
QX_PERSISTABLE_HPP(MyDerivedClass2)
public:
QString prop1;
QString prop2;
MyDerivedClass2() : MyBaseClass() { ; }
virtual ~MyDerivedClass2() { ; }
};
QX_REGISTER_HPP_QX_DLL2(MyDerivedClass2, MyBaseClass, 0)
typedef boost::shared_ptr<MyDerivedClass2> MyDerivedClass2_ptr;
---MyContainer.h文件:
class QX_DLL2_EXPORT MyContainer
{
public:
long id;
long base_id;
QString base_type;
MyBaseClass_ptr base_ptr;
MyContainer() : id(0), base_id(0) { ; }
virtual ~MyContainer() { ; }
void onBeforeInsert(qx::dao::detail::IxDao_Helper * dao);
void onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao);
void onBeforeDelete(qx::dao::detail::IxDao_Helper * dao);
void onBeforeFetch(qx::dao::detail::IxDao_Helper * dao);
void onAfterInsert(qx::dao::detail::IxDao_Helper * dao);
void onAfterUpdate(qx::dao::detail::IxDao_Helper * dao);
void onAfterDelete(qx::dao::detail::IxDao_Helper * dao);
void onAfterFetch(qx::dao::detail::IxDao_Helper * dao);
void insertOrUpdateBasePtr(qx::dao::detail::IxDao_Helper * dao);
};
QX_REGISTER_HPP_QX_DLL2(MyContainer, qx::trait::no_base_class_defined, 0)
typedef boost::shared_ptr<MyContainer> MyContainer_ptr;
namespace qx {
namespace dao {
namespace detail {
template <>
struct QxDao_Trigger<MyContainer>
{
static inline void onBeforeInsert(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onBeforeInsert(dao); } }
static inline void onBeforeUpdate(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onBeforeUpdate(dao); } }
static inline void onBeforeDelete(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onBeforeDelete(dao); } }
static inline void onBeforeFetch(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onBeforeFetch(dao); } }
static inline void onAfterInsert(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onAfterInsert(dao); } }
static inline void onAfterUpdate(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onAfterUpdate(dao); } }
static inline void onAfterDelete(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onAfterDelete(dao); } }
static inline void onAfterFetch(MyContainer * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onAfterFetch(dao); } }
};
} // namespace detail
} // namespace dao
} // namespace qx
---MyBaseClass.cpp文件:
QX_REGISTER_CPP_QX_DLL2(MyBaseClass)
namespace qx {
template <> void register_class(QxClass<MyBaseClass> & t)
{
t.id(& MyBaseClass::id, "id");
}}
MyBaseClass::~MyBaseClass() { ; }
---MyDerivedClass1.cpp文件:
QX_REGISTER_CPP_QX_DLL2(MyDerivedClass1)
QX_PERSISTABLE_CPP(MyDerivedClass1)
namespace qx {
template <> void register_class(QxClass<MyDerivedClass1> & t)
{
t.data(& MyDerivedClass1::description, "description");
}}
---MyDerivedClass2.cpp文件:
QX_REGISTER_CPP_QX_DLL2(MyDerivedClass2)
QX_PERSISTABLE_CPP(MyDerivedClass2)
namespace qx {
template <> void register_class(QxClass<MyDerivedClass2> & t)
{
t.data(& MyDerivedClass2::prop1, "prop1");
t.data(& MyDerivedClass2::prop2, "prop2");
}}
---MyContainer.cpp文件:
QX_REGISTER_CPP_QX_DLL2(MyContainer)
namespace qx {
template <> void register_class(QxClass<MyContainer> & t)
{
t.id(& MyContainer::id, "id");
t.data(& MyContainer::base_id, "base_id");
t.data(& MyContainer::base_type, "base_type");
}}
void MyContainer::onBeforeInsert(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
if (! base_ptr || ! base_ptr->qxClass()) { return; }
base_id = base_ptr->id;
base_type = base_ptr->qxClass()->getKey();
}
void MyContainer::onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
if (! base_ptr || ! base_ptr->qxClass()) { return; }
base_id = base_ptr->id;
base_type = base_ptr->qxClass()->getKey();
}
void MyContainer::onBeforeDelete(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
// Nothing to do here !
}
void MyContainer::onBeforeFetch(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
// Nothing to do here !
}
void MyContainer::onAfterInsert(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
insertOrUpdateBasePtr(dao);
}
void MyContainer::onAfterUpdate(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
insertOrUpdateBasePtr(dao);
}
void MyContainer::onAfterDelete(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
if (base_ptr)
{
QVariant idEmpty;
QSqlError daoError = base_ptr->qxDeleteById(idEmpty, (& dao->database()));
dao->updateError(daoError);
}
}
void MyContainer::onAfterFetch(qx::dao::detail::IxDao_Helper * dao)
{
if (! dao) { qAssert(false); return; }
if (dao->error().isValid()) { return; }
if ((base_id > 0) && (! base_type.isEmpty()))
{
MyBaseClass * pBase = qx::create_nude_ptr<MyBaseClass>(base_type);
if (! pBase) { qAssert(false); return; }
base_ptr.reset(pBase);
QVariant vId = base_id; QStringList lstEmpty;
QSqlError daoError = base_ptr->qxFetchById(vId, lstEmpty, lstEmpty, (& dao->database()));
dao->updateError(daoError);
}
}
void MyContainer::insertOrUpdateBasePtr(qx::dao::detail::IxDao_Helper * dao)
{
static bool bInEvent = false;
if (! base_ptr || bInEvent) { return; }
bInEvent = true;
QStringList lstEmpty; QVariant idEmpty;
QSqlError daoError; qx::QxSqlQuery queryEmpty;
qx_bool bExist = base_ptr->qxExist(idEmpty, (& dao->database()));
if (bExist)
{
daoError = base_ptr->qxUpdate(queryEmpty, lstEmpty, lstEmpty, (& dao->database()));
dao->updateError(daoError);
}
else
{
daoError = base_ptr->qxInsert(lstEmpty, (& dao->database()));
if (! daoError.isValid()) { daoError = qx::dao::update((* this), (& dao->database()), QStringList() << "base_id" << "base_type"); }
dao->updateError(daoError);
}
bInEvent = false;
}
---main.cpp文件进行一些测试:
daoError = qx::dao::create_table<MyDerivedClass1>(); qAssert(! daoError.isValid());
daoError = qx::dao::create_table<MyDerivedClass2>(); qAssert(! daoError.isValid());
daoError = qx::dao::create_table<MyContainer>(); qAssert(! daoError.isValid());
MyContainer b1;
MyDerivedClass1_ptr pD1 = MyDerivedClass1_ptr(new MyDerivedClass1());
pD1->description = "my desc";
b1.base_ptr = pD1;
daoError = qx::dao::insert(b1); qAssert(! daoError.isValid());
MyContainer b2;
MyDerivedClass2_ptr pD2 = MyDerivedClass2_ptr(new MyDerivedClass2());
pD2->prop1 = "my prop1";
pD2->prop2 = "my prop2";
b2.base_ptr = pD2;
daoError = qx::dao::insert(b2); qAssert(! daoError.isValid());
MyContainer b3;
b3.base_ptr = pD1;
pD1->description = "my desc modified";
daoError = qx::dao::insert(b3); qAssert(! daoError.isValid());
QList<MyContainer_ptr> all;
daoError = qx::dao::fetch_all(all);
qx::dump(all);
以及所有输出轨迹:
[QxOrm] sql query (0 ms) : CREATE TABLE MyDerivedClass1 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, description TEXT) [QxOrm] sql query (0 ms) : CREATE TABLE MyDerivedClass2 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, prop1 TEXT, prop2 TEXT) [QxOrm] sql query (16 ms) : CREATE TABLE MyContainer (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, base_id INTEGER, base_type TEXT) [QxOrm] sql query (0 ms) : SELECT MyDerivedClass1.id AS MyDerivedClass1_id_0 FROM MyDerivedClass1 WHERE MyDerivedClass1.id = :id [QxOrm] sql query (0 ms) : INSERT INTO MyDerivedClass1 (description) VALUES (:description) [QxOrm] sql query (0 ms) : UPDATE MyContainer SET id = :id, base_id = :base_id, base_type = :base_type WHERE id = :id_bis [QxOrm] sql query (3245 ms) : INSERT INTO MyContainer (base_id, base_type) VALUES (:base_id, :base_type) [QxOrm] sql query (0 ms) : SELECT MyDerivedClass2.id AS MyDerivedClass2_id_0 FROM MyDerivedClass2 WHERE MyDerivedClass2.id = :id [QxOrm] sql query (0 ms) : INSERT INTO MyDerivedClass2 (prop1, prop2) VALUES (:prop1, :prop2) [QxOrm] sql query (0 ms) : UPDATE MyContainer SET id = :id, base_id = :base_id, base_type = :base_type WHERE id = :id_bis [QxOrm] sql query (0 ms) : INSERT INTO MyContainer (base_id, base_type) VALUES (:base_id, :base_type) [QxOrm] sql query (0 ms) : SELECT MyDerivedClass1.id AS MyDerivedClass1_id_0 FROM MyDerivedClass1 WHERE MyDerivedClass1.id = :id [QxOrm] sql query (0 ms) : UPDATE MyDerivedClass1 SET id = :id, description = :description WHERE id = :id_bis [QxOrm] sql query (15 ms) : INSERT INTO MyContainer (base_id, base_type) VALUES (:base_id, :base_type) [QxOrm] sql query (0 ms) : SELECT MyDerivedClass1.id AS MyDerivedClass1_id_0, MyDerivedClass1.description AS MyDerivedClass1_description_0 FROM MyDerivedClass1 WHERE MyDerivedClass1.id = :id [QxOrm] sql query (0 ms) : SELECT MyDerivedClass2.id AS MyDerivedClass2_id_0, MyDerivedClass2.prop1 AS MyDerivedClass2_prop1_0, MyDerivedClass2.prop2 AS MyDerivedClass2_prop2_0 FROM MyDerivedClass2 WHERE MyDerivedClass2.id = :id [QxOrm] sql query (0 ms) : SELECT MyDerivedClass1.id AS MyDerivedClass1_id_0, MyDerivedClass1.description AS MyDerivedClass1_description_0 FROM MyDerivedClass1 WHERE MyDerivedClass1.id = :id [QxOrm] sql query (0 ms) : SELECT MyContainer.id AS MyContainer_id_0, MyContainer.base_id AS MyContainer_base_id_0, MyContainer.base_type AS MyContainer_base_type_0 FROM MyContainer [QxOrm] start dump 'QList<boost::shared_ptr<MyContainer>>' <QList-boost.shared_ptr-MyContainer-- class_id="0" tracking_level="0" version="0"> <count>3</count> <item class_id="1" tracking_level="0" version="1"> <px class_id="2" tracking_level="1" version="0" object_id="_0"> <id>1</id> <base_id>1</base_id> <base_type class_id="3" tracking_level="0" version="0">MyDerivedClass1</base_type> <base_ptr class_id="4" tracking_level="0" version="1"> <px class_id="6" class_name="MyDerivedClass1" tracking_level="1" version="0" object_id="_1"> <MyBaseClass class_id="5" tracking_level="1" version="0" object_id="_2"> <id>1</id> </MyBaseClass> <description>my desc modified</description> </px> </base_ptr> </px> </item> <item> <px class_id_reference="2" object_id="_3"> <id>2</id> <base_id>1</base_id> <base_type>MyDerivedClass2</base_type> <base_ptr> <px class_id="7" class_name="MyDerivedClass2" tracking_level="1" version="0" object_id="_4"> <MyBaseClass object_id="_5"> <id>1</id> </MyBaseClass> <prop1>my prop1</prop1> <prop2>my prop2</prop2> </px> </base_ptr> </px> </item> <item> <px class_id_reference="2" object_id="_6"> <id>3</id> <base_id>1</base_id> <base_type>MyDerivedClass1</base_type> <base_ptr> <px class_id_reference="6" object_id="_7"> <MyBaseClass object_id="_8"> <id>1</id> </MyBaseClass> <description>my desc modified</description> </px> </base_ptr> </px> </item> </QList-boost.shared_ptr-MyContainer--> [QxOrm] end dump 'QList<boost::shared_ptr<MyContainer>>'
- 如何将子类作为函数的参数传递给期望基类,然后将该对象传递到指向这些抽象类对象的指针向量中?
- 两个抽象类,派生自同一个基类.如何访问从一个抽象类到另一个抽象类的指针
- 删除指向抽象类的指针向量
- 如何将抽象类指针作为Q_PROPERTY?
- 为什么我可以取消引用指向抽象类的指针?
- 指向抽象类的指针数组:指向 nullptr 或不指向 nullptr (C++)
- C++ abort() 在函数内的抽象类对象指针调用上
- 抽象类和独特的指针
- 如何使用抽象类指针避免内存泄漏
- 如何从抽象类中删除指针
- 指向模板抽象类的指针向量
- 指针到抽象类的功能超载
- 使用抽象类时,如何正确删除指针
- 抽象类和唯一指针 c++ 错误
- 尝试在映射C++中存储指向抽象类的指针
- C++中的抽象类指针
- 如何将子类分配给函数中的抽象类指针
- 带有抽象类指针的c++对象副本
- 如何在c++中实现与抽象类指针向量的缓存一致性
- C++访问抽象类指针向量的子类的成员