モデルとORM
TreeFrogでは、モデルがORMオブジェクトを含むという関係になっています。つまり、has-aの関係です。他のほとんどのフレームワークでは、デフォルトで「ORMオブジェクト=モデル」になっていますから、ここは違っています。とはいうものの、できることは特に変わりません。TreeFrogでは、モデルオブジェクトはORMオブジェクトの小さいラッパーであると理解してください。
TreeFrogにはSqlObjectという名のO/Rマッピング(ORM)ライブラリが搭載されています。SqlObject向けに生成された「blogobject.h」を見てみましょう。
半分ほどおまじないコードがありますが、テーブルのフィールドがパブリックなメンバ変数として宣言されています。構造体に近いですね。たったこれだけで、CURD相当のメソッド(create, update, findFirst, remove)が使えるようになります。それらのメソッドはTSqlObjectクラスとTSqlORMapperクラスに定義されています。
class T_MODEL_EXPORT BlogObject : public TSqlObject, public QSharedData
{
public:
int id;
QString title;
QString body;
QDateTime created_at;
QDateTime updated_at;
int lock_revision;
enum PropertyIndex {
Id = 0,
Title,
Body,
CreatedAt,
UpdatedAt,
LockRevision,
};
int primaryKeyIndex() const { return Id; }
/*** Don't modify below this line ***/ // ここから下はおまじないマクロ
Q_OBJECT
Q_PROPERTY(int id READ getid WRITE setid)
T_DEFINE_PROPERTY(int, id)
Q_PROPERTY(QString title READ gettitle WRITE settitle)
T_DEFINE_PROPERTY(QString, title)
Q_PROPERTY(QString body READ getbody WRITE setbody)
T_DEFINE_PROPERTY(QString, body)
Q_PROPERTY(QDateTime created_at READ getcreated_at WRITE setcreated_at)
T_DEFINE_PROPERTY(QDateTime, created_at)
Q_PROPERTY(QDateTime updated_at READ getupdated_at WRITE setupdated_at)
T_DEFINE_PROPERTY(QDateTime, updated_at)
Q_PROPERTY(int lock_revision READ getlock_revision WRITE setlock_revision)
T_DEFINE_PROPERTY(int, lock_revision)
};
TreeFrogのO/Rマッピングライブラリにはプライマリキーでの照会や更新を行うメソッドがありますが、SqlObjectが持てるプライマリキーはprimaryKeyIndex()メソッドで返す1つだけです。従って、複数プライマリキーをもつテーブルでは、1つ選んでこの値を修正してください。
また、TCriteriaクラスを使うことで、より複雑な条件を指定してクエリを発行することも可能です。
では、モデルのヘッダを見てみましょう。
各プロパティのセッター/ゲッターと、オブジェクトの生成/取得の静的メソッドが定義されています。親クラスのTAbstractModelに保存(save())と削除(remove())のメソッドが定義されているので、結果としてBlogクラスにはCRUD相当のメソッド(create, get, save, remove)が備わっています。
class T_MODEL_EXPORT Blog : public TAbstractModel
{
public:
Blog();
Blog(const Blog &other);
Blog(const BlogObject &object); // ORM オブジェクト指定のコンストラクタ
~Blog();
int id() const; // ここからセッター、ゲッターが並ぶ
void setId(int id);
QString title() const;
void setTitle(const QString &title);
QString body() const;
void setBody(const QString &body);
QDateTime createdAt() const;
QDateTime updatedAt() const;
int lockRevision() const;
static Blog create(int id, const QString &title, const QString &body); // オブジェクト生成
static Blog create(const QHash<QString, QString> &values); // Hash でプロパティを渡してオブジェクト生成
static Blog get(int id); // ID 指定でモデルオブジェクトを取得
static Blog get(int id, int lockRevision);
static QList<Blog> getAll(); // モデルオブジェクトを全取得
private:
QSharedDataPointer<BlogObject> d; // ORM オブジェクトのポインタを持つ
TSqlObject *data();
const TSqlObject *data() const;
};
Q_DECLARE_METATYPE(Blog) // おまじない
Q_DECLARE_METATYPE(QList<Blog>)
まとめ
ジェネレータで自動生成されたコードはそんなに多くないステップ数にも関わらず、基本的な機能ができあがっています。当然ながら生成されたコードは完全ではなく、実際のアプリケーションではさらに複雑な処理になるはずなので、そのままは使えないことが多いかもしれません。手直しが必要でしょう。ジェネレータは、コードを書く手間を少々省く程度のものと考えてください。
TreeFrog Frameworkは開発が始まってまだ日が浅く、成熟していない部分もあります。完成度を上げるために、皆さんからの要望や意見をうまく取り入れながら、開発を続けていきたいと思っています。そして、いつかTreeFrog Frameworkが企業でも採用されるWebアプリケーションフレームワークになれるように努めていきたいと思います。
参考情報
TreeFrog Frameworkのホームページにも情報はあるのでご覧ください。
