QtのORMの概要

はじめに



こんにちは、プログラマーの皆さん!

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が好きな人にとって、このコードは知り合いにとって非常に興味深いものです。

例、コード、説明から判断すると、次の機能が実装されています。

長所:

短所:

逆説的に、すべての不利な点を除けば、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ではありません。 テーブルフィールドにマップするクラスフィールドを構成することはできません。 割り当てのみを使用してデータベースにデータを直接(から)書き込む(読み取る)ことはできません。 しかし、あなたは他の多くのことをすることができます。

機会、彼らは図書館のプラスです。

短所? もちろん、たくさんあります!


一般的に、ライブラリはまだ開発中ですが、すでに多くのことを知っています。 私は仕事でそれを使用します。 フリーランサーとして別のプロジェクトを書いています。 一般に、例のソースコードからわかるように、プログラマーは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 ( ) ) ;
}

Source: https://habr.com/ru/post/J105191/


All Articles