[odb-users] Inheritance

Kuentzer, Jan jan.kuentzer at roche.com
Wed Aug 17 12:06:40 EDT 2011


Hi Boris,

Thanks again for the workaround for the polymorphic inheritance which works fine with the current release. 
I use as you suggested id fields with transient pointer. I implemented a callback method for post_load and pre_persist. The persist works fine and the ids are correctly written in the database. But I found a strange behavior with the post_load which I cannot explain.

I have a derived class (e.g. node_set) having a polymorphic variable with the type of the super class (e.g. node). This means the variable could actually be of the same type as the class itself (e.g. the node could be a node_set). If this is the case, the load method is not working. If the attribute is of another type everything is loaded perfectly fine. Is this a problem of the callback method since I load an object of the same type? If I load the attribute alone by id outside the callback method everything works fine. 

Best

        Jan



> 
> The idea behind emulation is to encode the object type into the id. This
> way, when you load the object, you can first figure out its actual type
> and then load it from the database. In this approach you cannot use the
> automatically-assigned ids for the hierarchy, and all objects in the
> hierarchy must share the same id space.
> 
> As an example, let's use a 64-bit integer as an id for our employee
> hierarchy. To encode the object type, we will reserve the top byte
> and will use 1 for permanent_employee and 2 for temporary_employee
> (employee class is abstract and doesn't need a type code).
> 
> #pragma db object abstract
> class employee
> {
> public:
>   ...
> 
>   unsigned long long
>   id () const
>   {
>     return id_;
>   }
> 
> protected:
>   friend class odb::access;
>   employee () {} // Default c-tor for ODB.
> 
>   // C-tor for derived types.
>   //
>   employee (unsigned char type_code, unsigned long long id)
>   {
>     id = (type_code << 56) | (id & 0x00FFFFFFFFFFFFFFUL);
>   }
> 
>   #pragma db id
>   unsigned long long id_;
> };
> 
> #pragma db object
> class permanent_employee
> {
> public:
>   permanent_employee (unsigned long long id)
>     : employee (1 /* type code for permanent_employee */, id)
>   {
>   }
> 
>   ...
> 
> };
> 
> #pragma db object
> class temporary_employee
> {
> public:
>   temporary_employee (unsigned long long id)
>     : employee (2 /* type code for temporary_employee */, id)
>   {
>   }
> 
>   ...
> 
> };
> 
> Next we need to wrap the database operation with some extra logic.
> Here is polymorphic persist:
> 
> unsigned long long
> persist_employee (odb::database& db, employee* e)
> {
>   switch (d->id () >> 56) // Get the type code.
>   {
>   case 1:
>     return db->persist (static_cast<permanent_employee*> (e));
>   case 2:
>     return db->persist (static_cast<temporary_employee*> (e));
>   default:
>     assert (false);
>   }
> };
> 
> And here is polymorphic load() (note that id should be what's returned
> by the persist() call or what's stored in employee::id_, not what we
> pass to *_employee constructors).
> 
> employee*
> load_employee (odb::database& db, unsigned long long id)
> {
>   switch (id >> 56) // Get the type code.
>   {
>   case 1:
>     return db->load<permanent_employee*> (id);
>   case 2:
>     return db->load<temporary_employee*> (id);
>   default:
>     assert (false);
>   }
> }
> 
> Finally, in order to have a polymorphic object relationship, you will
> need to emulate it by having a persistent member that is the object
> id and a transient member which is the actual pointer:
> 
> #pragma db object
> class employer
> {
>   ...
> 
>   unsigned long long ceo_id_;
> 
>   #pragma db transient
>   employee* ceo_;
> };
> 
> You will then need to use the load_employee() function to load the ceo_
> pointer. For the next release of ODB we have added support for user
> callbacks. This feature will allow you to handle such loading
> transparently.
> 
> Boris



More information about the odb-users mailing list