Support of inheritance

Forum for posting problems using QxOrm library

Support of inheritance

Postby ukindler » Sun Dec 05, 2010 10:14 am

QxOrm 1.1.3 builds fine with MinGW and all test cases work properly so I would like to integrate QxOrm into a project here. It is the first time I work with ORM so I have some questions about some things I'm not really shure about from reading the tutorial and the tests code.

From reading the code and the tutorial I would assume, that inhertitance is supported by QxOrm. In my application I have the folowing inheritance hirarchy:

Code: Select all
// the interface
class IContainer
{
}

// has some data related to all containers that may contain fluid
class CFluidContainer : public IContainer
{
}

// this is a leaf in the inheritance hierarchy that implements a real container
class CTank : public CFluidContainer
{
}

// that is a leaf in the inheritance hierarchy for storage of pipettes
class CPipetteContainer : public IContainer
{
}


Now in my application I need to work with the plain IContainer interface and I also need to work with the implementations (i.e. CTank). That means, I would like to read all containers from database into a container collection.

Is this possible with QxOrm. How is this implemented in the database? Does QxOrm create a table for each derived class? It would be create if the samples or the tutorial could be enhanced to show how to work with inheritance.

I tried the exe-dll1-dll2 test because it works with inheritance (CUser is derived from CPerson). But if I insert a CUser via qx::dao::insert(pUser) like it is done in the exe source then the CUser table contains 1 entry and the CPerson table is empty. So where is the data stored of the base class CPerson? Is there something I'm doing wrong?
ukindler
 

Re: Support of inheritance

Postby QxOrm admin » Sun Dec 05, 2010 2:32 pm

Hi,

With ORM tools, there is typically 3 ways to map inheritance on database :

1- Single Table Inheritance
Single Table Inheritance from the database perspective uses a single table with a discriminator column to determine which type each row contains. The table must contain columns for all the attributes required by any subclasses.

2- Class Table Inheritance
Class Table Inheritance involves using different tables for each class where the "base" table defines the primary key, and the others "inherit" it.

3- Concrete Table Inheritance
Concrete Table Inheritance is a third way to map a class hierarchy, each concrete class has it's own database table.

QxOrm 1.1.3 works with "2- Class Table Inheritance" and "3- Concrete Table Inheritance".

I recommend to use "3- Concrete Table Inheritance" with QxOrm 1.1.3.
You just have to add the following line in your "qx setting function" :

template <> void register_class(QxClass<???> & t)
{
[i]t.setDaoStrategy(QX_TABLE_PER_HIERARCHY);

//...
}[/i]


PS : points "1-" and "2-" to use inheritance with QxOrm and databases will be improve in the next release...
QxOrm admin
 

Re: Support of inheritance

Postby ukindler » Sun Dec 05, 2010 7:20 pm

Hi,

thank you for the explanation.

In the german Wikipedia is written about Concrete Table Inheritance:

The attributes of the abstract base class are put into the tables for the concrete derived classes. The table for the base class is not required. The disadvantage of this approach is that it is not possible to get instances of different classes with one query.


Does this mean, that I can't execute a query that returns a collection of my abstract base class IContainer where I can cast the interface to the concrete class later?

And a last question about class registering. To properly support my inheritance hierarchy I need to write the following code for all classes in my inheritance hierarchy (for IContainer, for CFluidContainer and for CTank)?

Code: Select all
template <> void register_class(QxClass<???> & t)
{
    t.setDaoStrategy(QX_TABLE_PER_HIERARCHY);
//...
}


Is this right? Or do I have to call setDaoStrategy(QX_TABLE_PER_HIERARCHY) only for the abstract base class IContainer?

Thank you for your help.
ukindler
 

Re: Support of inheritance

Postby ukindler » Mon Dec 06, 2010 7:13 am

Hi,

I have some additional questions regarding inheritance. You wrote that you recommend "Concrete Table Inheritance" with QxOrm 1.1.3. That means I would need to call t.setDaoStrategy(QX_TABLE_PER_CLASS) when registering my class and because QX_TABLE_PER_CLASS is the default setting I do not need to set it explicitely - is this right?

Let us assume I would use the following inhertiance hierarchy (example)

Code: Select all
// abstract interface
class InterfaceA
{
}

// concrete class B with data member B
class ClassB : public InterfaceA
{
protected:
    int m_ID;
    int m_B;
}

// concrete class C with data member C (data member B derived from ClassB)
class ClassC : public ClassB
{
protected:
    int m_C;
}


Because I have two concrete classes, for "Concrete Table Inheritance" I would need to create two tables:

Code: Select all
QSqlError daoError = qx::dao::create_table<ClassB>();
daoError = qx::dao::create_table<ClassC>();


Is this right so far?

No I would need to register my classes the following way:

Code: Select all
namespace qx {
template <> void register_class(QxClass<ClassB> & t)
{
   IxDataMember * pData = NULL;
   t.setName("ClassB");
   pData = t.id(& ClassB::m_ID, "ID", 0);
   pData = t.data(& ClassB::m_B, "B", 0);
}}

// Register data members of C and base class B because this ClassC has its own table with all data members
namespace qx {
template <> void register_class(QxClass<ClassC> & t)
{
   IxDataMember * pData = NULL;
   t.setName("ClassC");
   pData = t.id(& ClassC::m_ID, "ID", 0);
   pData = t.data(& ClassC::m_B, "B", 0);
   pData = t.data(& ClassC::m_C, "C", 0);
}}


That means for "Concrete Table Inheritance" it is necessary to register the data members of the base class and the derived class because all data is stored in one table for one concrete class. Is this right or am I wrong here?

Because the data is stored in different tables I cannot read all InterfaceA classes with one query but I have to query each concrete class table to build up a collection of InterfaceA classes. Is this right?

Thank you for any help. I know that are many questions but If you start with something completely new, then there is always a steep learning curve.
ukindler
 

Re: Support of inheritance

Postby QxOrm admin » Mon Dec 06, 2010 9:12 am

No, you are right to ask all your questions.
This is not very explicit in quick sample and tutorial of the web site.
And this is a "little young" in QxOrm library => it needs to be improve...

The flag "QX_TABLE_PER_HIERARCHY" means to point "3- Concrete Table Inheritance".
This is not the default and this is problably a mistake in the library.
The flag "QX_TABLE_PER_HIERARCHY" indicates to QxOrm to retrieve all properties of base class to build sql queries.
So you will have 1 table in your database per concrete class.
So, this flag is not required in your interface (or abstract class) because there is no base class (but you can write it, it changes nothing).
But the flag "QX_TABLE_PER_HIERARCHY" is required in all your derived classes to use strategy "3- Concrete Table Inheritance".
This is problably the most easy and useful strategy in all ORM tools.

The default strategy in QxOrm is "QX_TABLE_PER_CLASS" => "2- Class Table Inheritance".
But you will have some problems with this strategy if you don't add some code in your classes.
So I don't recommend to use this strategy today with QxOrm 1.1.3.

In your sample, you have an interface "InterfaceA", and 2 classes : "ClassB" and "ClassC".
You don't have to repeat properties of "classB" in the registering function of "classC" (I think you will have an "assert()").
But it is necessary to add the flag "QX_TABLE_PER_HIERARCHY" to use "3- Concrete Table Inheritance".

Code: Select all
namespace qx {
template <> void register_class(QxClass<ClassB> & t)
{
   t.setDaoStrategy(QX_TABLE_PER_HIERARCHY);
   t.id(& ClassB::m_ID, "ID", 0);
   t.data(& ClassB::m_B, "B", 0);
}}

namespace qx {
template <> void register_class(QxClass<ClassC> & t)
{
   t.setDaoStrategy(QX_TABLE_PER_HIERARCHY);
   t.data(& ClassC::m_C, "C", 0);
}}


In your database, you need 2 tables :
"TableB" with columns : "ID", "B"
"TableC" with columns : "ID", "B" and "C"

=> You need to query "TableB" and "TableC" to retrieve all your "InterfaceA" in a collection (so yes => 2 queries in this case).
Maybe you can add some virtual methods to your "interfaceA" to manage your database :

Code: Select all
 virtual QSqlError saveToDatabase() = 0;
 virtual QSQlError getAllFromDatabase() = 0;
 etc...


BE CAREFUL, DON'T USE "qx::create_table" :
I recommend to manage your database with an IDE provided by your SGBD to create table : pgAdmin with PostGreSQL, Navicat with MySQL, SQLite manager with SQLite, etc...
There is no problem to build sql query to search, insert, update or delete (standard SQL).
But to create a table, this is very specific for each SGBD and QxOrm has been tested only with SQLite.
QxOrm admin
 

Re: Support of inheritance

Postby ukindler » Mon Dec 06, 2010 3:16 pm

Hi,

thank you for your help. I tested QX_TABLE_PER_HIERARCHY with the dll1-dll2-exe test (CPerson -> CUser) and everything worked fine. I created the first table for CPerson and the second table for CUser with all columns from CPerson + the columns from CUser. When I insert a CUser it properly inserts the data of base and derived class ;O) - great.

Thank you for you help. Now I can start playing around with QxOrm and try to integrate it into my project.

Thank you for all your help so far. QxOrm is rellay greate IMHO - I did not find a C++ ORM with comparable capabilities.
ukindler
 

Re: Support of inheritance

Postby QxOrm admin » Mon Dec 06, 2010 4:11 pm

Thank you for all your tests.

I will change the tutorial to talk about dao strategy and inheritance.
In the next release, I think this is better to set default value to "QX_TABLE_PER_HIERARCHY".
And in the next release, QxOrm will support 3 strategies to manage inheritance :
1- Single Table Inheritance
2- Class Table Inheritance
3- Concrete Table Inheritance
QxOrm admin
 

Re: Support of inheritance

Postby ukindler » Mon Dec 06, 2010 6:50 pm

That sounds realy great. :D
ukindler
 


Return to QxOrm - Help

Who is online

Users browsing this forum: No registered users and 8 guests