はじめに
こんにちは、プログラマーの皆さん!
Qtの世界では、ここ1年間、非常に興味深いイベントが開催されています。 ここには、バージョン4.7の最新リリース、QMLの概念、およびモバイルプラットフォームへのライブラリの重要な統合があります。 Qtには最も正しいトロールがあります。 私は彼らが何をしていて、このライブラリがどこで開発されているかが好きです。 私は彼女が彼女のクラスで最高だと確信していますが、Qtで書いている人はすでにこれを知っています。
年間を通じて変化している何かがあります。 Qtの場合、ORMライブラリがキノコのように次々と現れ始めました。 聖地は空ですか? 需要があります、ここにオファーがあります。 この記事でQt ORMの世界で何が起こっているかを読んでください。 監視対象のライブラリで使用される使用法とメカニズムに関する最大限の情報を提供するようにします。 しかし、ORMはプログラミングソリューションの非常に複雑なセットであるため、それらの1つを完全に奉献することはできません。
(この記事は、私自身のORMのために掲載されたため、やや宣伝的なものであることに注意してください。最善の意図)。
QxOrm、ver。 1.1.1
著者/所有者 :QxOrm France
サイト :
公式 、
SourceForgeでライセンス :GPLv3 +商用
依存関係 :Qt(4.5+)、ブースト(1.38+)
開発期間 :2010年の初め、最後の変更は2010年4月です
ドキュメント :不完全、フランス語
例 :はい、最も基本的な
開発の主な目標は 、永続性(QtSql経由)、シリアル化(boost ::シリアル化経由)、およびリフレクションのメカニズムを提供することです。ライブラリは非常に強力に見え、多くのことを実行できるようです。 DAO(
データアクセスオブジェクト )の原理に基づいて構築され、テーブルに行を表示するクラスがあり、いくつかのメソッドを使用すると、そのような行のリストがデータベースから取得されます。 これを可能にするために、QxOrmは、テンプレート(多くのテンプレート)、マクロ、継承、単純な複数を含む非常にトリッキーなメカニズムを使用します。 あなたがプログラミングのトリックが好きな人や、たとえばAlexandrescuが好きな人にとって、このコードは知り合いにとって非常に興味深いものです。
例、コード、説明から判断すると、次の機能が実装されています。
- 任意のstl / boostコンテナーにテーブルデータを表示します。 Qtコンテナーもこのトリックを行うと思います。
- 複雑なキャッシング。
- 最も単純なクエリの生成:挿入、更新、削除、テーブルの作成、そしてもちろん選択。
- 独自のQxSqlQueryであるQSqlDatabaseをラップします。
- コードレベルでの1対1、1対多、多対多の関係。
- ハッシュ、キーおよび値によるソートを使用して、キー/値タイプのstlのようなQxCollectionコレクションを所有します。
- foreach(!)ループのテンプレート実装。その原理は推測することしかできません。
- テンプレートシングルトンを実装しました。
長所:
- 一般的な焦点はデータベースではなく、XMLを含む抽象的なストレージにあります。 確かに、これは「バズーカからのスズメに」というブーストによって達成されます。
- 選択した値を直接コンテナに渡す、優れたORM機能。
- 一連の追加機能:シリアル化、コンテナ、キャッシュなど
- マッパーを操作するための単純な構文。 作者は、インターフェースを設計するときに存在する何かに導かれたことがわかります。 すべてが論理的で、きちんとしていて、BoostとSTLに非常に似ています。 Qtスタイルは最小限です。
- 技術ライブラリ; ただし、内部キッチンを調べるのは非常に難しいため、これはまさにマイナスです。
短所:
- 一般的な焦点はデータベースではなく、抽象ストレージです。
- 弱いSQLサポート。 特に、WHERE、JOIN、GROUP BY、ORDER BYなどの生成はありません。 たとえば、フィルターによって特定のデータを抽出するには、それらすべてを選択してから、STL / Boostアルゴリズムを適用する必要があります。 (しかし、私はすべてについて確信がありません;多分何かを見逃したかもしれません。それにもかかわらず、ソースコードにはWHERE生成がありません-これは事実です。)
- 弱いドキュメント。 おそらく著者は、十分な例とチュートリアルがあると信じていますが、私はそうは思いません。 私たちQtプログラマーは、優れた完全なドキュメントに慣れています。 クラス、メソッド、または定数の説明はありません。 まあ、何が-フランス語で。
- ライブラリの関与。 あなたがそこにあなた自身の何かを追加できることを望んでさえいません。
- 中毒を後押しします。
- 免許 これは、彼女が完全に自由だと言うことではありません。 ライブラリベースの製品を販売したいですか? 著者に支払います。
- 主なもの:ライブラリは開発中ではなく、ドキュメントは翻訳されていません。 著者は、最初に外国のインターネットでQxOrmを広く宣伝し、その後姿を消しました。 バージョン1.1.1が最初で唯一でした。
逆説的に、すべての不利な点を除けば、QxOrmはほとんど唯一のQtと互換性のある本格的なORMソリューションです。 そしてこれは、複雑なプロジェクトにとって重要なキャッシングがある唯一のソリューションです。 他のORMがQxOrmと比較される可能性は低いため、この小さなレビューは他のレビューよりも多いことがわかります。 ただし、大規模プロジェクトでライブラリを使用する場合、特に抽象リポジトリではなく本格的なDBMSで作業している場合は、他の可能性が必要になる場合がありますが、そうではありません。 何らかのバグを修正したいと思うでしょう-しかし、それはそれほど単純ではありません。 たくさんの自転車と松葉杖を発明する必要があります。 プロジェクトは必然的にキメラになります。 それどころか、いくつかの優れた機能だけが必要な小さなプロジェクトの場合、ライブラリは有用です。Boostを引き締めることを恐れない範囲で。
マッパークラスの例(すべてのコードはドキュメントから取得されます):
クラス薬
{
公開 :
長い ID ;
QString名;
QStringの説明。
drug ( ) : id ( 0 ) { ; }
仮想 〜薬物( ) { ; }
} ;
QX_REGISTER_HPP_MY_TEST_EXE ( drug、qx :: trait :: no_base_class_defined 、 1 )
QX_REGISTER_CPP_MY_TEST_EXE ( drug ) //このマクロは、QxOrmコンテキストで 'drug'クラスを登録するために必要です
名前空間 qx {
テンプレート <> void register_class ( QxClass < drug > & t )
{
t。 id ( & drug :: id 、 "id" ) ; // 'drug :: id' <=>主キーをデータベースに登録します
t。 data ( & drug :: name 、 "name" 、 1 ) ; //キー 'name'およびバージョン '1'で 'drug :: name'プロパティを登録します
t。 data ( & drug :: description 、 "desc" ) ; // 'drug :: description'プロパティをキー 'desc'に登録します
} }
使用例:
//ドラッグを保存するためにデータベースにテーブル「ドラッグ」を作成します
QSqlError daoError = qx :: dao :: create_table < drug > ( ) ;
//コンテナからデータベースに薬物を挿入します
//「d1」、「d2」、「d3」の「id」プロパティは自動更新されます
daoError = qx :: dao :: insert ( lst_drug ) ;
// 2番目の薬物を変更してデータベースに更新します
d2- > name = "name2 modified" ;
d2- > description = "desc2 modified" ;
daoError = qx :: dao :: update ( d2 ) ;
//データベースから最初の薬物を削除します
daoError = qx :: dao :: delete_by_id ( d1 ) ;
//データベースに薬を数えます
long lDrugCount = qx :: dao :: count < drug > ( ) ;
// ID「3」のドラッグを新しい変数に取得します
drug_ptr d_tmp ; d_tmp。 リセット (新薬( ) ) ;
d_tmp- > id = 3 ;
daoError = qx :: dao :: fetch_by_id ( d_tmp ) ;
//コンテナからXML形式のファイルに薬物をエクスポート(シリアル化)
qx :: シリアル化 :: xml :: to_file ( lst_drug、 "./export_drugs.xml" ) ;
// xmlファイルから新しいコンテナにドラッグをインポートします
type_lst_drug lst_drug_tmp ;
qx :: シリアライゼーション :: xml :: from_file ( lst_drug_tmp、 "./export_drugs.xml" ) ;
//薬物のクローン
drug_ptr d_clone = qx :: clone ( * d1 ) ;
//クラス名で新しい薬を作成します(工場)
boost :: any d_any = qx :: create ( "drug" ) ;
//ドラッグコンテナを 'qx :: cache'に挿入します
qx :: キャッシュ :: set ( "drugs" 、lst_drug ) ;
QDjango、ver。 ???
投稿者 :JeremyLainé、Bollorételecom
サイト :
公式 、
メーリングリストライセンス :GPLv3、LGPLv3
依存関係 :Qt(4.5+)
2010年6月3日から
開発中ドキュメンテーション :完全な英語のdoxygen生成
例 :はい、最も基本的です。
主な目標 :可能な限りDjangoに似た、Qt用の無料のORMを作成すること。この開発の長所と短所について話すのは時期尚早ですが、ライブラリはまだ方法を知りません。 どうやら、これはDAO / Active Record-ORMになります。 現在、SELECTの生成、コンテナへのデータの取得、CREATE TABLE生成によるテーブルの作成がすでに可能です。 著者はすぐにWHERE生成を規定し始めました。 さらに、ANDおよびOR演算子がサポートされています。 つまり、マルチレベルフィルターを作成でき、フィルターを設定するための構文も成功します。 開発では、QxOrmと同じメソッドが積極的に使用されます:テンプレート、継承...それらに基づいて、おそらく、著者は優れたOOPコードの巨大なファームを作成するでしょう。
しかし、それだけです。 私たちは、1年半で強力なORMシステムがQDjangoから成長すると信じていますが、今のところ、プロジェクトでのそのアプリケーションについて話す必要はありません。
著者からの使用例。
//すべてのユーザー
QDjangoQuerySet <ユーザー> users ;
//パスワードが「foo」で、ユーザー名が「bar」ではないすべてのユーザーを検索します
QDjangoQuerySet < User > someUsers ;
someUsers =ユーザー。 filter ( QDjangoWhere ( "password" 、QDjangoWhere :: Equals 、 "foo" ) &&
QDjangoWhere ( "username" 、QDjangoWhere :: NotEquals 、 "bar" ) ) ;
//ユーザー名が「foo」または「bar」であるすべてのユーザーを検索します
someUsers =ユーザー。 filter ( QDjangoWhere ( "username" 、QDjangoWhere :: Equals 、 "foo" ) ||
QDjangoWhere ( "username" 、QDjangoWhere :: Equals 、 "bar" ) ) ;
//ユーザー名が「f」で始まるすべてのユーザーを検索します。
someUsers =ユーザー。 filter ( QDjangoWhere ( "username" 、QDjangoWhere :: StartsWith 、 "f" ) ) ;
//結果の数を制限する
someUsers =ユーザー。 制限 ( 0、100 ) ;
//一致するユーザーの数を取得します
int numberOfUsers = someUsers。 サイズ ( ) ;
//最初に一致したユーザーを取得します
ユーザー* firstUser = someUsers。 at ( 0 ) ;
//空きメモリ
firstUserを削除します。
//一致するユーザーのユーザー名とパスワードのリストを取得します
QList < QList < QVariant >> propertyLists = someUsers。 valuesList ( QStringList ( ) << "username" << "password" ) ;
//クエリセット内のすべてのユーザーを削除します
someUsers。 削除 ( ) ;
ユーザークラス:
クラス User : public QDjangoModel
{
Q_OBJECT
Q_PROPERTY ( QStringユーザー名READユーザー名WRITE setUsername )
Q_PROPERTY ( QStringパスワードREADパスワードWRITE setPassword )
Q_CLASSINFO ( "ユーザー名" 、 "最大長= 255" )
Q_CLASSINFO ( "password" 、 "max_length = 128" )
公開 :
QStringユーザー名( ) const ;
void setUsername ( const QString & username ) ;
QString password ( ) const ;
void setPassword ( const QString & password ) ;
プライベート :
QString m_username ;
QString m_password ;
} ;
QtPersistence、ver。 0.1.1
投稿者 :マット・ロジャース
サイト :
SourceForgeでライセンス :LGPLv3
依存関係 :Qt(4.5+)
開発期間 :2009年末-2010年初頭
ドキュメント :なし
例 :単体テストで悪い
主な目標 :Rubyのいくつかの(?)ORMと同様に、Active Recordアプローチに基づいてQtのORMを作成します。ほとんど何も知らない別のライブラリ。 さらに悪いことに、開発されません。 著者はこのプロジェクトを放棄したようです。 実際、彼女ができることは、マッパークラスを使用してデータベースにデータを書き込むことだけです。
使用例は、単体テスト(自己記述型テストモジュールに基づく)にあります。
クラス FakeBook : public QPersistantObject
{
Q_OBJECT
Q_PROPERTY ( QString著者READ著者WRITE setAuthor )
Q_PROPERTY ( int yearPublished READ yearPublished WRITE setYearPublished )
公開 :
Q_INVOKABLE FakeBook ( QObject * parent = 0 ) : QPersistantObject ( parent ) { }
virtual〜FakeBook ( ) { }
void setAuthor ( const QString & a ) { m_author = a ; }
QString author ( ) const { return m_author ; }
void setYearPublished ( int year ) { m_yearPublished = year ; }
int yearPublished ( ) const { return m_yearPublished ; }
プライベート :
QString m_author ;
int m_yearPublished ;
} ;
FakeBook * b = 新しい FakeBook ;
b- > setAuthor ( "Matt Rogers" ) ;
b- > setYearPublished ( 2009 ) ;
bool objectSaved = b- > save ( ) ;
削除 b ;
ASSERT_TRUE ( objectSaved ) ;
b = 新しい FakeBook ;
b- > setAuthor ( "マットロジャースではない" ) ;
b- > setYearPublished ( 1999 ) ;
objectSaved = b- > save ( ) ;
削除 b ;
ASSERT_TRUE ( objectSaved ) ;
QsT SQLツール(QST)、ver。 0.4.2aリリース
投稿者 :Alexander Granin(me :))
サイト :
SourceForgeの フォーラムライセンス :GPLv3、LGPLv3
依存関係 :Qt(4.5+)
2009年9月から
開発中ドキュメンテーション :完全な、doxygen生成、ロシア語のみ
例 :コードでは、単体テストです。 また、バージョン0.3および0.4用の特別なTradeDBサンプルプロジェクト(本格的なデータベースアプリケーション)も作成しました。
主な目標は、Qtでのデータベースアプリケーションのプログラミングを容易にすることです。ORMについて話すのは簡単ではありません。 サンドボックスに記事を書いて、Habrに着いたのは彼女のおかげでした。
記事は興味をそそりませんでした...しかし、それはバージョン0.3でした-そして、リリースさえしませんでしたが、プレアルファです。 今、私はQSTの開発にかなり踏み込んでおり、0.5.1プレアルファ版は既に利用可能です。 しかし、まだやるべきことがたくさんあります。
まず第一に、これは通常のORMではありません。 私はライブラリーを書き始めましたが、用語はまだわかりませんでした。 クエリを作成せず、1つの層に集中させるために、クエリを生成するためのツールが必要でした。クエリを追跡するのが簡単でした。 Active Recordのようなアプローチについては知りませんでした。 その結果、何が起こったのかがわかります。それは独特のORMであり、正確なORMではありません。 テーブルフィールドにマップするクラスフィールドを構成することはできません。 割り当てのみを使用してデータベースにデータを直接(から)書き込む(読み取る)ことはできません。 しかし、あなたは他の多くのことをすることができます。
機会、彼らは図書館のプラスです。
- SELECT、INSERT、UPDATE、DELETE、EXECUTEなどの単純な(非階層の意味で、ガジェットなしの)SQLクエリの生成(PostgreSQLの場合、これはSELECTです)。
- DFDコンセプト¬–宣言型フィールド記述子。 それに応じて、リクエストを生成する方法を説明します。 さらに、SELECTでは、受信したデータをQt表現(QTableView、QListView、QComboBox)で使用する方法を説明します。
- Qtインタビューとの統合。 いくつかありますが、あります。 非アクティブレコードアプローチに加えて、これはQSTとその他すべての主な違いです。 たとえば、特定のクエリに対するQTableView列の幅、資格の付与方法を指定できます。 または、一部のビューで現在の行に関連付けられているデータ値を選択できます。
- 複数の名前付きクエリ。
- 各リクエストに対して-多くの異なるビューを接続する機能。
- WHEREセクションの生成。 フィルタは非常に異なって設定できます。 メインマイナス:AND演算子を使用して条件を結合する必要があります。
- 「max(field_name)」、「sum(price * count)as summa」と指定されている場合、フィールド名を自動的に取得します。 前者の場合、フィールドには完全にアクセスできます(「max(field_name)」)と省略形(「field_name」)の両方です。 2番目のケースでは、「summa」のみを使用します。
- 多機能接続クラスは、QSqlDatabaseのラッパーです。 接続テストを実行し、設定を保存し、異なる名前で接続し、接続を削除できます。
- 一般的に、簡単に使用できます。 主なことは、ライブラリの動作の意味を理解することです。
- ツリーデータモデル。 私は本当にこの形式で自分のライブラリを新しく削除したくないので、最終的に書き換えたいと思っています。 これは可能な範囲を超えており、より安全なメモリ操作につながります。
- パス「プログラム-DB」上のデータの変換を間接的に促進します。
- SQL生成をチューニングするための非常に広範な機能。 たとえば、フィルタを含めることで将来のクエリを記述した場合、フィルタが無効な場合、単に生成されません。 ただし、有効な場合はSQLダイアレクトの形式に縮小され、WHEREセクションに追加されます。 比較ファンクターも自動的に配置されます。 文字列の場合はLIKE、数字の場合は「=」です。 ただし、簡単にオーバーライドできます。
- その他。
短所? もちろん、たくさんあります!
- 珍しい概念、アイデンティティ。 手で多くのことをしなければなりません。 より正確には、ハンドラクラスを作成し、さまざまな種類のクエリのDFDを記述します。
- SQLのサポートは、レビューされたすべてのライブラリよりも多くありますが、まだ不十分です。 今、私はいくつかのタスクで戦っています。 おそらく次のバージョンでは、生成エンジンが書き直されるでしょう。
- キャッシング、シリアル化、リフレクションはありません。実際のオブジェクトリレーショナルマッピングはありません。 関係を作成する方法はありません(関係:1:1、1:n、n:n)。 これで、私は認めなければなりません、QxOrmは他の先を行っています。
- キャッシングなし。 より良い実装方法を考えていますが。
- 他のすべてのORMで考えられていたほど簡単にデータを構造に取得することはできません。 ただし、QSTアプローチ自体は、個々のデータセットについては考えないことを示唆しています。 代わりに、特定のレコードの個々の値だけでなく、モデルと表現のレベルで考えることをお勧めします。
- ライブラリは他のライブラリほど技術的ではありません。 はい、内部にはテンプレートと継承の両方がありますが、これは同じQxOrmと比較しても何もありません。 いずれにせよ、プログラマはこれを気にする必要はありません。
- いずれにせよ、最初にいくつかの非自明性。 多くのことは自動的に行われ(変換など)、完全なドキュメントにもかかわらず、すぐにこれに気付かないことがあります。
- その他。
一般的に、ライブラリはまだ開発中ですが、すでに多くのことを知っています。 私は仕事でそれを使用します。 フリーランサーとして別のプロジェクトを書いています。 一般に、例のソースコードからわかるように、プログラマーはQxOrmまたはQDjangoを使用するプログラマーよりも作業がはるかに少なくなります。 ハンドラーの説明、ビューのロード-ほとんどすべてがメインクラス(QstAbstractModelHandler)にある機能を取得します。 私はゆっくりと必要なものをすべて紹介しますが、いつでも私に頼ることができます、私は間違いなく助けます。 とは対照的に。 したがって、私はこの困難な事業で私をサポートすることを控えめに提案します。 幸運の願いでもありますが; より良い-すべてのレビュー。 ありがたいです。
SELECTクエリのハンドラクラスとDFD記述子の例。
QstFieldフィールドは、ビューのカスタマイズに関する情報(フィールドの表示可能性、タイトル、列幅)も送信することに注意してください。
// personshandler.h
const int PERSONS = 1 ;
const int PERSONS_FULL_NAME = 2 ;
クラス PersonsHandler : public QstAbstractModelHandler
{
プライベート :
QstBatch _selector ( const int & queryNumber ) const ;
QstBatch _executor ( const int & queryNumber ) const ;
} ;
// personshandler.cpp
QstBatch PersonsHandler :: _selector ( const int & queryNumber ) const
{
QstBatchバッチ;
if ( queryNumber == PERSONS )
{
バッチ。 addSource ( "vPersons" ) ;
batch << QstField ( RolePrimaryKey、 "ID" )
<< QstField ( "Address_ID" )
<< QstField ( "LastName" 、FieldVisible、 "Last Name" 、 100 )
<< QstField ( "FirstName" 、FieldVisible、 "Name" 、 100 )
<< QstField ( "ParentName" 、FieldVisible、 "ミドルネーム" 、 100 )
<< QstField ( "vcBirthDate" 、FieldVisible、 "Date \ n Birth" 、 90 )
<< QstField ( "Phone" 、FieldVisible、 "Contact \ n Phone" 、 120 )
<< QstField ( "[E-Mail]" 、FieldVisible、 "e-mail" 、 120 )
<< QstField ( "ID" 、値( ID_VALUE ) 、PurposeWhere )
;
}
他に
if ( queryNumber == PERSONS_FULL_NAME )
{
バッチ。 addSource ( "vPersons" ) ;
バッチ
<< QstField ( "FullName" 、FieldVisible、 "Full Name" 、 300 )
<< QstField ( "LastName" 、FieldVisible、 "Last Name" 、 100 )
<< QstField ( "FirstName" 、FieldVisible、 "Name" 、 100 )
<< QstField ( "ParentName" 、FieldVisible、 "ミドルネーム" 、 100 )
<< QstField ( "vcBirthDate" 、FieldVisible、 "Date \ n Birth" 、 90 )
<< QstField ( "Phone" 、FieldVisible、 "Contact \ n Phone" 、 120 )
<< QstField ( "[E-Mail]" 、FieldVisible、 "e-mail" 、 120 )
<< QstField ( "ID" 、値( ID_VALUE ) 、PurposeWhere )
<< QstField ( RolePrimaryKey、 "ID" )
<< QstField ( "Address_ID" )
;
}
他に
{
Q_ASSERT ( 偽 ) ;
}
バッチを返し ます。
}
ビューのカスタマイズ:
// PersonsHandler _personsHandler;
// QstPlainQueryModel _personsModel; //-PersonsFormクラスで説明されています。
void PersonsForm :: loadPersons ( )
{
_personsHandler。 reload ( PERSONS、 & _personsModel ) ;
_personsHandler。 setTableView ( ui- > tv_PersonsTableView ) ;
}
QVariant PersonsForm :: personID ( ) const
{
_personsHandlerを返します。 keyValueOfView ( ) ;
}
使用法:
void PersonsForm :: loadPersonalDocumentInfo ( )
{
PersonalDocumentsHandler th ;
番目。 setValue ( "Person_ID" 、personID ( ) ) ;
QVariantMap valMap = th。 SelectToMap ( PERSONAL_DOCUMENTS、
QStringList ( )
<< "DocTypeName"
<< "シリアル番号"
<< 「番号」
<< "vcIssueDate"
<< "GivenBy" ) ;
ui- > le_DocumentTypeLineEdit- > setText ( valMap [ "DocTypeName" ] 。 toString ( ) ) ;
ui- > le_SerialNumberLineEdit- > setText ( valMap [ "SerialNumber" ] 。 toString ( ) ) ;
ui- > le_NumberLineEdit- > setText ( valMap [ "Number" ] 。 toString ( ) ) ;
ui- > le_IssueDateDateEdit- > setDate ( valMap [ "vcIssueDate" ] 。 toDate ( ) ) ;
ui- > le_GivenByLineEdit- > setText ( valMap [ "GivenBy" ] 。 toString ( ) ) ;
}