[odb-users] Circular relation problem with external file mapping

Boris Kolpackov boris at codesynthesis.com
Tue Jul 23 06:06:10 EDT 2013


Hi Romain,

Romain Gros <grosr.romain at gmail.com> writes:

> I'll try to make QuestStep a composite value type when I have some time.
> 
> But we have a lot of object organized like that, because of the protobuf,
> and I'm not sure we can do this for everything !

This is conceptually the correct way to map it. In ODB, objects are
independent entities, they are not contained by other objects. In
contrast, values are always part of some object. Even your vocabulary
suggest that QuestStep is a value that is part of the Quest object
(i.e., it is called QuestStep (Quest's Step), not just Step).

You may also want to read Section 3.1, "Concepts and Terminology" for
more information on this distinction.


> Moreover, I really want to learn how your ORM work, so if you have some
> time to tell me about the other way, I would appreciate knowing it !

The idea is to use lazy pointers and virtual data members to make
ODB think there is a vector of pointers to objects. The trick is
then to implement accessors and modifiers in such a way that they
take object ids from lazy pointers and load the object state
directly into the "contained" data members. Here is an outline:

struct Quest;

#pragma db object
struct QuestStep
{
  ...

  Quest* quest_;
};

#pragma db object
struct Quest
{
  ...

  #pragma db transient
  std::vector<QuestStep> steps_;

  typedef std::vector<odb::lazy_ptr<QuestStep>> QuestStepPointers;

  #pragma db member(steps) virtual(QuestStepPointers) inverse(quest_) \
             get(steps_value_to_ptr) set(steps_ptr_to_value)

  QuestStepPointers
  steps_value_to_ptr () const
  {
    QuestStepPointers r;
   
    for (std::vector<QuestStep>::const_iterator i (steps_.begin ());
         i != steps_.end ();
         ++i)
    {
      // Initialize lazy_ptr with a pointer to steps_ element.
      //
      r.push_back (&*i);
    }
  }

  void
  steps_ptr_to_value (const QuestStepPointers& ps)
  {
    for (QuestStepPointers::const_iterator i (ps.begin ()); 
         i != ps.end (); 
         ++i)
    {
      // Load object state directly into steps_ element.
      //
      steps_.push_back (QuestStep ());
      i->database ().load (steps_.back (), i->object_id<QuestStep> ());
    }
  }
};

As you can see, pretty involved but I guess also pretty cool at some
level. The things one can do with virtual data members keep surprising
me.

Boris



More information about the odb-users mailing list