What is the best way to extend a DBO class without affecting other DBO classes?
Added by Plug Gulp over 1 year ago
Say I have following DBO classes:
class MyDbo
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::belongsTo(a, other_dbo_);
}
private:
Wt::Dbo::ptr<OtherDbo> other_dbo_;
};
class OtherDbo
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::hasMany(a, my_dbo_, Wt::Dbo::ManyToOne);
}
private:
Wt::Dbo::collection<Wt::Dbo::ptr<MyDbo>> my_dbo_;
};
Now, I want to extend the OtherDbo
class and create an inherited class OtherDboEx
. If I do that, then I have to modify MyDbo
class too by replacing OtherDbo
with OtherDboEx
. Is here a way in which I can extend a current DBO class(OtherDbo
) without having to modify other DBO classes(MyDbo
) that references the DBO class that is being extended?
Replies (4)
RE: What is the best way to extend a DBO class without affecting other DBO classes? - Added by Roel Standaert over 1 year ago
The Wt::Dbo::ptr
type is indeed not covariant, since relational databases don't have inheritance.
There are multiple ways you could model inheritance hierarchies in relational databases. Wt::Dbo
does not provide particular abstractions for that, so those are things you would have to model manually.
You could for example add another table that only has the data that's specific to a particular subclass: https://web.csulb.edu/colleges/coe/cecs/dbdesign/dbdesign.php?page=subclass.php
So you'd have:
class OtherDbo
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::hasMany(a, my_dbo_, Wt::Dbo::ManyToOne);
}
private:
Wt::Dbo::collection<Wt::Dbo::ptr<MyDbo>> my_dbo_;
};
class OtherDboEx
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::belongsTo(a, super_);
}
private:
Wt::Dbo::ptr<OtherDbo> super_;
};
RE: What is the best way to extend a DBO class without affecting other DBO classes? - Added by Plug Gulp over 1 year ago
Thank you for the reply. The link provided in the reply is very helpful as well!
For the solution suggested above, I presume there will be a performance hit due to join
on every query?
One example where this inheritance is useful is when there is a base architecture such as tag_table
, post_table
, comment_table
and user_table
. So the Dbo
classes for this will be:
class tag_table
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::belongsTo(a, creator_);
Wt::Dbo::hasMany(a, posts_, Wt::Dbo::ManyToMany, "post_tags");
}
private:
Wt::Dbo::ptr<user_table> creator_;
Wt::Dbo::collection<Wt::Dbo::ptr<post_table>> posts_;
};
class post_table
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::belongsTo(a, creator_);
Wt::Dbo::hasMany(a, tags_, Wt::Dbo::ManyToMany, "post_tags");
Wt::Dbo::hasMany(a, comments_, Wt::Dbo::ManyToOne);
}
private:
Wt::Dbo::ptr<user_table> creator_;
Wt::Dbo::collection<Wt::Dbo::ptr<tag_table>> tags_;
Wt::Dbo::collection<Wt::Dbo::ptr<comment_table>> comments_;
};
class comment_table
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::belongsTo(a, creator_);
Wt::Dbo::belongsTo(a, post_);
Wt::Dbo::belongsTo(a, parent_, "parent");
Wt::Dbo::hasMany(a, comments_, Wt::Dbo::ManyToOne, "parent");
}
private:
Wt::Dbo::ptr<user_table> creator_;
Wt::Dbo::ptr<post_table> post_;
Wt::Dbo::ptr<comment_table> parent_;
Wt::Dbo::collection<Wt::Dbo::ptr<comment_table>> comments_;
};
class user_table
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::hasMany(a, created_tags_, Wt::Dbo::ManyToOne);
Wt::Dbo::hasMany(a, created_posts_, Wt::Dbo::ManyToOne);
Wt::Dbo::hasMany(a, created_comments_, Wt::Dbo::ManyToOne);
}
private:
Wt::Dbo::collection<Wt::Dbo::ptr<tag_table>> created_tags_;
Wt::Dbo::collection<Wt::Dbo::ptr<post_table>> created_posts_;
Wt::Dbo::collection<Wt::Dbo::ptr<comment_table>> created_comments_;
};
Now, say, I want to extend this base design with the requirement that a user can report tag
, post
and comment
. So following report_table
s will have to be created:
template <typename content_type>
class report_table
{
public:
template <typename action>
auto persist(action &a)
{
Wt::Dbo::belongsTo(a, creator_);
Wt::Dbo::belongsTo(a, reported_content_);
}
private:
Wt::Dbo::ptr<user_table> creator_;
Wt::Dbo::ptr<content_type> reported_content_;
};
using tag_report_table = report_table<tag_table>;
using post_report_table = report_table<post_table>;
using comment_report_table = report_table<comment_table>;
This now forces me to modify all the classes in the base design! If I extend the classes as per the suggestion above, then there will be performance penalty(due to join
) when accessing the tables?
RE: What is the best way to extend a DBO class without affecting other DBO classes? - Added by Plug Gulp over 1 year ago
BTW, just forgot to ask. Regarding the solution suggested above for extending the table OtherDbo
; the relation between OtherDbo
and OtherDboEx
will be one-to-one, so will the class OtherDbo
not have to be modified to reflect that relationship?
RE: What is the best way to extend a DBO class without affecting other DBO classes? - Added by Roel Standaert over 1 year ago
OtherDbo
may have a backreference to OtherDboEx
with hasOne
through a weak_ptr
, yes. It's not strictly necessary, since the belongsTo
side makes sure it's in the database schema.
I'm not 100% sure if it may also be possible to use Wt::Dbo::id
in OtherDboEx
, so you can simply use the id
column in OtherDboEx
to refer back to OtherDbo
.