Note that there are some explanatory texts on larger screens.

plurals
  1. POPersistence classes in Qt
    text
    copied!<p>I'm porting a medium-sized CRUD application from .Net to Qt and I'm looking for a pattern for creating persistence classes. In .Net I usually created abstract persistence class with basic methods (insert, update, delete, select) for example:</p> <pre><code>public class DAOBase&lt;T&gt; { public T GetByPrimaryKey(object primaryKey) {...} public void DeleteByPrimaryKey(object primaryKey) {...} public List&lt;T&gt; GetByField(string fieldName, object value) {...} public void Insert(T dto) {...} public void Update(T dto) {...} } </code></pre> <p>Then, I subclassed it for specific tables/DTOs and added attributes for DB table layout:</p> <pre><code>[DBTable("note", "note_id", NpgsqlTypes.NpgsqlDbType.Integer)] [DbField("note_id", NpgsqlTypes.NpgsqlDbType.Integer, "NoteId")] [DbField("client_id", NpgsqlTypes.NpgsqlDbType.Integer, "ClientId")] [DbField("title", NpgsqlTypes.NpgsqlDbType.Text, "Title", "")] [DbField("body", NpgsqlTypes.NpgsqlDbType.Text, "Body", "")] [DbField("date_added", NpgsqlTypes.NpgsqlDbType.Date, "DateAdded")] class NoteDAO : DAOBase&lt;NoteDTO&gt; { } </code></pre> <p>Thanks to .Net reflection system I was able to achieve heavy code reuse and easy creation of new ORMs.</p> <p>The simplest way to do this kind of stuff in Qt seems to be using model classes from QtSql module. Unfortunately, in my case they provide too abstract an interface. I need at least transactions support and control over individual commits which QSqlTableModel doesn't provide.</p> <p>Could you give me some hints about solving this problem using Qt or point me to some reference materials?</p> <hr> <p><strong>Update:</strong></p> <p>Based on Harald's clues I've implemented a solution that is quite similar to the .Net classes above. Now I have two classes.</p> <p><em>UniversalDAO</em> that inherits <em>QObject</em> and deals with <em>QObject</em> DTOs using metatype system:</p> <pre><code>class UniversalDAO : public QObject { Q_OBJECT public: UniversalDAO(QSqlDatabase dataBase, QObject *parent = 0); virtual ~UniversalDAO(); void insert(const QObject &amp;dto); void update(const QObject &amp;dto); void remove(const QObject &amp;dto); void getByPrimaryKey(QObject &amp;dto, const QVariant &amp;key); }; </code></pre> <p>And a generic <em>SpecializedDAO</em> that casts data obtained from <em>UniversalDAO</em> to appropriate type:</p> <pre><code>template&lt;class DTO&gt; class SpecializedDAO { public: SpecializedDAO(UniversalDAO *universalDao) virtual ~SpecializedDAO() {} DTO defaultDto() const { return DTO; } void insert(DTO dto) { dao-&gt;insert(dto); } void update(DTO dto) { dao-&gt;update(dto); } void remove(DTO dto) { dao-&gt;remove(dto); } DTO getByPrimaryKey(const QVariant &amp;key); }; </code></pre> <p>Using the above, I declare the concrete DAO class as following:</p> <pre><code>class ClientDAO : public QObject, public SpecializedDAO&lt;ClientDTO&gt; { Q_OBJECT public: ClientDAO(UniversalDAO *dao, QObject *parent = 0) : QObject(parent), SpecializedDAO&lt;ClientDTO&gt;(dao) {} }; </code></pre> <p>From within <em>ClientDAO</em> I have to set some database information for <em>UniversalDAO</em>. That's where my implementation gets ugly because I do it like this:</p> <pre><code>QMap&lt;QString, QString&gt; fieldMapper; fieldMapper["client_id"] = "clientId"; fieldMapper["name"] = "firstName"; /* ...all column &lt;-&gt; field pairs in here... */ dao-&gt;setFieldMapper(fieldMapper); dao-&gt;setTable("client"); dao-&gt;setPrimaryKey("client_id"); </code></pre> <p>I do it in constructor so it's not visible at a first glance for someone browsing through the header. In .Net version it was easy to spot and understand.</p> <p>Do you have some ideas how I could make it better?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload