1

I am writing applications in C++ using an sqlite database. Suppose I have a simple user system with a user database.

User Class

class User {
    private:
        void LoadFromDatabase(uint32_t id);
    public:
        std::string name;
        uint32_t age;
        void SayHello();
        void SetAge(uint32_t age);
};

User Table

+-------+-----+
| Name  | Age |
+-------+-----+
| Billy |  22 |
| Bob   |  44 |
+-------+-----+

When getting data from the database, I like to store things in row objects so it's super easy to figure out what's in the row (otherwise its a pointer to a char array and you'd have to know what each column index is). This is where the redundancy problem comes in.

User Row

class UserRow {
    public:
        std::string name;
        uint32_t age;
};

So now I have repeated the class properties between two classes. This is obviously a trivial example, but sometimes rows have 10 or more columns. One solution would be to get rid of UserRow and just pass around User, but the database shouldn't really know anything about User and be as dumb as possible. Another solution could be to have User.properties which is = to a UserRow, but that makes it less accessible.

What would be the best way to avoid these duplicate fields/classes?

  • 1
    Just use User where you would use UserRow. Both classes contain exactly the same data, and you don't have to call the SayHello and SetAge functions if you don't need to. – Robert Harvey Aug 30 '18 at 21:56
  • I don't want to post this as a full answer because it doesn't exactly answer the question, but note that if User is a domain object and UserRow a data transfer object, there's no architectural need to remove the redundancy. Sure, it's slightly annoying, but it has the advantage of being more flexible in light of future changes. – Sebastian Redl Aug 31 '18 at 7:52
  • How are you binding the UserRow? with a TypeHandler? – Ewan Aug 31 '18 at 8:22
  • @SebastianRedl: I don't believe that this kind of gained flexibility is worth the admittedly annoying redundancy in most cases. Shouldn't the database reflect the domain model. Why should anyone modify the database without modifying the domain objects as well? Yes, there might be special cases where it makes sense but should we build our software architecture around special cases? – Frank Puffer Aug 31 '18 at 10:06
  • @FrankPuffer The database might be independent of the application. Modification usually happens the other way round: the domain objects get modified, but the database stays the same to avoid the need for data migration. And finally, in DDD, there may be multiple object-based views of the same table, i.e. multiple user entities that reflect some part of the user table/DTO. – Sebastian Redl Aug 31 '18 at 14:44
5

Look at this approach :

class User {
    private:
        UserRow userRow;
        void LoadFromDatabase(uint32_t id); // init userRow
    public:
        std::string GetName(){return userRow.name;}
         // implement setName in an analogous manner
        uint32_t getAge(){return userRow.age;}
         // setAge ...
        void SayHello();
        void SetAge(uint32_t age);
};

The advantage is, the code for UserRow can be created by some generator in a standard manner, just by utilizing the meta data from a database. UserRow then becomes your data access layer (DAL), User, however, is a class of your domain layer.

Moerover, you should consider to move LoadFromDatabase to another place, like into some repository class, to make the class User persistent-ignorant.

1

You could say that your User objects actually are row objects, since they already have the same information. Like you have done now, You have only created an unnecessary abstraction layer which doesn't provide anything useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.