Project

General

Profile

What is the best way to extend a DBO class without affecting other DBO classes?

Added by Plug Gulp about 2 years 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 about 2 years 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 about 2 years 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_tables 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 about 2 years 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 about 2 years 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.

    (1-4/4)