[CONTAINERNET-79] Quill単独でトランザクション処理・S2Dao.NETの利用を行えるようにする Created: 2007-12-10  Updated: 2008-07-29  Resolved: 2008-07-29

Status: Resolved
Project: S2Container.NET
Component/s: Quill
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: sugimotokazuya Assignee: koyak
Resolution: Fixed Votes: 0
Labels: None

Attachments: Zip Archive source.zip    

 Description   

QuillのシンプルなDIとAOPでは実現が難しいので、専用の属性を作ろうかと考えています。



 Comments   
Comment by koyak [ 2008-07-29 ]

ドキュメントを整理し終わってからResolveとしようかと考えていましたが、
そちらの方は別タスクとしておこうと思います。

Comment by koyak [ 2008-04-06 ]

ここでの変更内容(データソース、アセンブリ、S2Dao、トランザクションの設定)について
ドキュメントを追加しました。
http://s2container.net.seasar.org/ja/quill.html#nodicon

QuillTestCaseについてはまだ書いていないのですが・・・
そちらはまた後日ということで。

Comment by koyak [ 2008-03-11 ]

> 2. QuillTestCaseを継承し忘れるとNullReferenceExceptionなので明示的な例外が欲しい
例外を投げるようにしました。

また、接続文字列の取得時に、外部からのファイル読み込みなどの
処理を入れられるようにしてほしい、という要望があったため、
Seasar.Quill.Database.Datasource.Connection.IConnectionStringインターフェースを追加しました。

以下のように指定するとDataSourceBuilderクラスの中でインスタンスを生成(この場合はDummyConnectionString)し、
IConnectionStringがもつGetConnectionStringメソッドを呼び出して接続文字列を取得します。
> <dataSources>
> <dataSource name="Hoge1">
> <provider>SqlServer</provider>
> <connectionString>Seasar.Tests.Quill.DummyConnectionString</connectionString>
> <class>Seasar.Extension.Tx.Impl.TxDataSource</class>
> </dataSource>
> </dataSources>

従来のように文字列で直接指定したい場合は「"」で囲みます。
> <dataSources>
> <dataSource name="Hoge1">
> <provider>SqlServer</provider>
> <connectionString>"Server=localhost;database=s2dotnetdemo;Integrated Security=SSPI"</connectionString>
> <class>Seasar.Extension.Tx.Impl.TxDataSource</class>
> </dataSource>
> </dataSources>

Comment by jflute [ 2008-03-07 ]

> 例:
> <dataSources>
> <dataSource name="Hoge1">
> <provider>SqlServer</provider>
> <connectionString>(local)\Hoge1</connectionString>
> <class>Seasar.Extension.ADO.Impl.DataSourceImpl</class>
> </dataSource>
> </dataSources>

のclassをSeasar.Extension.Tx.Impl.TxDataSourceに変えたらOKでした。
ドキュメント書くときに気をつけておいて下さい。

> 2. QuillTestCaseを継承し忘れるとNullReferenceExceptionなので明示的な例外が欲しい
まあ、後でもいいです。
ただ、忘れてないように別課題にして下さい。
こういうのすごく大事なことなので。

さあ、あともうちょい!頑張って!

Comment by jflute [ 2008-03-07 ]

3番はテストで使ってるMySQLの環境かとも思ったけど、
同じ環境を使ってるJava版の方のテストではロールバックがうまくいってます。

Comment by jflute [ 2008-03-07 ]

1. QuillTestCaseTestがコミットされてない!?
2. QuillTestCaseを継承し忘れるとNullReferenceExceptionなので明示的な例外が欲しい
3. ロールバックのログは出力されるけど実際のデータがロールバックされてない!?(調査中...)

Comment by koyak [ 2008-03-07 ]

コミットしました。

QuillContainerでdiconなしテストを実行したい場合は
[Test, Quill]
もしくは
[Test, Quill(Tx.Rollback)]
というように属性をテストメソッドに付けます。
(クラスにはTestFixture)

テストを実行すると
QuillTestCaseRunnerのRunメソッドが呼び出され、
その中でQuillInjector.Injectを呼び出しQuillTestCaseを継承したテストクラスに
大してInjectionを行います。

Seasar.Test.Quill.Unit.QuillTestCaseTestにて動作確認しています。

Comment by jflute [ 2008-03-06 ]

おお、コミットしたら早速DBFluteNBasicExampleで試しますよ。

Comment by koyak [ 2008-03-06 ]

>杉本さん
ご確認ありがとうございます。
このまま作業を続けます。

>「S2TestCaseRunner」を参考に「QuillTestCaseRunner」を作るか、
>「S2TestCaseRunner」自体を修正してQuill対応しちゃうか、
>悩みそうですが、前者の方が紛らわしくないかなとは思います。

QuillTestCaseRunnerを作る方向で。
元々大きめな処理なのでこれ以上if文を加えると複雑になってしまうのではないかと思います。
他にQuillAttribute、QuillTestCase、QuillTestCaseRunInvoker
も同様に作成しています。
それに伴い、SetupDataSourceなどのS2TestCaseRunnerなどが
もっているメソッドの一部をvirtualに修正する予定です。

[Test, Quill(Tx.Rollback)]で中身空っぽのテストが動くことは
とりあえず確認済み。

Comment by sugimotokazuya [ 2008-03-05 ]

特に問題ないと思います。
よろしくお願いします。>小谷さん

Comment by jflute [ 2008-03-02 ]

残り課題:

> B. リリース後でもよい:
>
> B-1. DynamicProxyがGenericのメソッドをサポートしていない
> B-2. 指定が両方無い場合のエラーメッセージ

は、次回でも良いでしょう。別課題にしちゃって下さい。
(DBFlute的には「B-1」がちょとだけ痛いのですが...)

固定的な複数DB対応は、既に別課題になっていますが、
それも次回で良いでしょう。。

なので、あとは「テストケースでのトランザクション」と「ドキュメント」ですね。

テストケースは、
「S2TestCaseRunner」を参考に「QuillTestCaseRunner」を作るか、
「S2TestCaseRunner」自体を修正してQuill対応しちゃうか、
悩みそうですが、前者の方が紛らわしくないかなとは思います。
そこは任せます。

Comment by jflute [ 2008-03-02 ]

「Y」に関して動作確認取れました。

あとは、単体テストでのトランザクションをどうするかかな!?

Comment by jflute [ 2008-03-02 ]

> MySQL.Dataを追加しても駄目ですか?

もともと追加されています。それでダメでした。

> 自分の環境ではそれでMySqlConnectionクラスなどのインスタンスを
> ForNameで取得できました。

まあ、他の人の環境でOKならOKではあるので優先度下げますか。
VS Expressだからかな!?
dbflute-nbasic-exampleで試してもらえると助かります。

Yに関しては動作確認取れたらコミットしてOKです。
こちらでもさらに動作確認しますので。

Comment by koyak [ 2008-03-02 ]

<X>テストの初期化時に以下を実行しないと例外になってしまった。
テストに使っているプロジェクトの参照設定に
MySQL.Dataを追加しても駄目ですか?
自分の環境ではそれでMySqlConnectionクラスなどのインスタンスを
ForNameで取得できました。

>また、問題の本質とは別に、ForName()の戻り値nullは明示的な例外にしたほうが良い。
これは確かに。
ただやるとしたら別タスクですね。

<Y>
こちらは自分のローカルでは対応しました。
quillセクションでデータソースが指定されていたら
ConnectionStringやdiconの設定は使いません。

quillセクションに定義がなければ
ConnectionStringを見ます。
ここで指定されていればdiconの設定は使いません。

どちらにも定義がなければdiconの設定を使います。

注・まだコミットはしていません。

Comment by jflute [ 2008-02-27 ]

テストケースのトランザクションは、Seasar.UnitのS2TestCaseRunnerをそのまま間借りするか、
コピペでQuill側に持ってきてちょこっと書き換えるかでいいと思われる。
(後者でいいね)

Comment by jflute [ 2008-02-26 ]

エンコーディングがバラバラになってるかな!?
Quill(だけ)は「UTF-8」で実装されていたのだが、
今見るとMS932が混じってるかな。

Comment by jflute [ 2008-02-26 ]

<X>
テストの初期化時に以下を実行しないと例外になってしまった。

System.Reflection.Assembly.Load("MySQL.Data, version=1.0.10.1, Culture=neutral, PublicKeyToken=c58...");

例外箇所は、Seasear.Extension.ADO.DataProviderDataSource#GetConnection()で、
ConnectionTypeのForName()の戻り値がnullになってしまっている。
アセンブリのロードの解決って、どうすれば良いだろうか???

また、問題の本質とは別に、ForName()の戻り値nullは明示的な例外にしたほうが良い。

<Y>
connectionStringsタグでremove name="LocalSqlServer"をやらないと例外になってしまう。
優先度がconnectionStringsが先になっているためと思われるが、デフォルトでLocalSqlServerが
存在しているので、わざわざ消さないとquillタグの方が有効にならないようである。
優先度は、quillタグの方を先にしても良いのでは?

上記2点以外は、今のところちゃんと動いています。
「A」の問題は解決されているようです。

> ThreadLocalではなく、通常のインスタンス変数とし、
> 別スレッドからでも設定したデータソース名を見ることができるようにしました。

この話は別途検討した方が良いかもね

Comment by koyak [ 2008-02-26 ]

↑Aについては対応しました。
A-2についてはデータソース名を設定したものとは別スレッドで
データソースに接続しようとすると発生します。
ThreadLocalではなく、通常のインスタンス変数とし、
別スレッドからでも設定したデータソース名を見ることができるようにしました。
(この場合はマルチスレッドでシビアなタイミングでデータソース名を
変更しようとすると誤動作する可能性をもつことになります。要検討?)

DataSourceはquillセクションの中のdataSourcesタグ内で
指定できるようにしています。

name属性→データソースを特定する一意の名前
providerタグ→使用するDataProvider継承クラス名(
 デフォルトはSeasar.Quill.Database.Provider内のクラスを参照する)
connectionString→接続文字列
class→データソースクラス名

例:
<dataSources>
<dataSource name="Hoge1">
<provider>SqlServer</provider>
<connectionString>(local)\Hoge1</connectionString>
<class>Seasar.Extension.ADO.Impl.DataSourceImpl</class>
</dataSource>
</dataSources>

connectionStringタグも引き続き使用できるようにしています。
こちらを使った場合はTxDataSourceが使われるように変更しました。
ただ、TxDataSourceの場合は(quillセクションを使った場合も含めて)
S2Dao属性単独ではNullReferenceExceptionとなります。
(TransactionContextが定義されていないため)
Transaction属性をどこか一箇所でも使っていれば動きます。

Comment by koyak [ 2008-02-22 ]

ありがとうございます。
特にAについては早いうち(日曜くらいに)対応したいと思います。

Comment by jflute [ 2008-02-22 ]

課題をまとめます。

A. 対応しないとリリースしちゃいけない:

A-1. 全てのDataProviderを指定可能なConnection指定
A-2. 1回実行後、もう一回実行したら例外発生
A-3. 「provider」というコンソールログが出る

B. リリース後でもよい:

B-1. DynamicProxyがGenericのメソッドをサポートしていない
B-2. 指定が両方無い場合のエラーメッセージ

Comment by jflute [ 2008-02-22 ]

2点:

<1>
provider
provider
DEBUG (Logger#Log():0) - Logical connection closed
provider
DEBUG (Logger#Log():0) - Logical connection got
provider
provider

というコンソールログが出る

<2>
1回実行後、もう一回実行したら例外発生

Message: [ESSR0071]SQLException occured, because Seasar.Framework.Exceptions.EmptyRuntimeException:
[ESSR0007] at slot should not be null or empty
場所 Seasar.Extension.ADO.Impl.AbstractSelectableDataSourceProxy.GetDataSource()
場所 Seasar.Extension.ADO.Impl.AbstractSelectableDataSourceProxy.GetConnection()
場所 Seasar.Framework.Util.DataSourceUtil.GetConnection(IDataSource dataSource)

※2番は致命的

Comment by jflute [ 2008-02-22 ]

DynamicProxyがGenericのメソッドをサポートしていない!?
(でも頑張ればできるみたい)
http://forum.springframework.net/showthread.php?t=644

現在、DaoでGenericありのメソッドを作ると以下のような例外になります。

Message: アセンブリ 'DynamicAssemblyProxyGen, Version=0.0.0.0, Culture=neutral, PublicKeyToken=f362209d9bee91d8' からの型 'ProxyInterfaceSystemSystemObject_DfExample_DBFlute_AllCommon_CBean_OutsideSqlOutsideSqlDao_System_Runtime_SerializationISerializable' にあるメソッド 'SelectList' に実装が含まれていません。

Comment by jflute [ 2008-02-22 ]

App.configでのConnectionの指定とado.diconの指定が両方無い場合に、
しばらく処理が帰ってこないでタイムアウトになります。
優先度は低で良いですが、「Connectionの設定がありません」な
エラーになった方がよいです。

Comment by jflute [ 2008-02-22 ]

> DB接続文字列とデータプロバイダの部分ですが
> App.config標準機能のDB接続文字列を指定する方法ではだめでしょうか?
> http://s2container.net.seasar.org/ja/db-appconfig.html#AppConfig

一つは、ドキュメントの記述例の補足として「SQLServerの例」と
書いておいた方がいいと思いました。

もう一つは、この方式をサポートしているDataProviderが少ないのではないかと懸念します。
少なくとも試したらMySQL Connector/Netはダメっぽいです。
少なくともOracle/DB2/SQLServer/MySQL/PostgreSQL/Firebirdで
「フリーでこれに対応したDataProvider」が無ければつらいかなと思います。
無論、このやり方はあっても良いですが、別途独自の方法での指定が
あった方がよいです。(最初に小谷が実装したやり方とか)

Comment by koyak [ 2008-02-22 ]

コミットしました。
複数データソースでトランザクションかけた場合のテストを
まだ入れていないのですが、それは来週のタスクとさせて下さい。
(金土日は都合により作業できないので)

S2DaoAttributeとTransactionAttributeで行っているテストは
AspectBuilderに書くべきだったかもしれません。
(今はSeasar.Test.Quill.Attr下で新規にテストクラスを作って書いています)
その辺も来週見直します。

Comment by jflute [ 2008-02-20 ]

ある程度のテストができたら、DBFluteの方でも実装始めたいと思います。
すると、別角度からのテストにもなるので。

Comment by koyak [ 2008-02-20 ]

>App.config標準機能のDB接続文字列を指定する方法ではだめでしょうか?
>http://s2container.net.seasar.org/ja/db-appconfig.html#AppConfig

・上記機能を使ってデータソース設定を実装しました。
(お陰様でコード量が減りました!)

・Transaction属性に渡す型はITransactionSetting実装クラスにしました。
(AbstractTransactionSettingも用意しました)
・S2Dao属性に渡す型はIDaoSetting実装クラスにしました。
(AbstractDaoSettingも用意しました)

どちらも
1.属性の引数で渡されたXxxSetting
2.app.configで指定されたクラス
3.TypicalXxxSettingクラス
の優先順で設定が適用されます。

あとはテスト・・・?

Comment by jflute [ 2008-02-19 ]

> SQLに関するあれこれを設定することと
> トランザクションをかけることは同じDB絡みでも別モノかと

同意。

> Transaction属性の引数に渡すものを少し変えて、
> DaoSettingと同様にTransactionSettingを渡してもらって
> 設定するのはいかがでしょう?
> (なければ例のごとくapp.configから探す)

同じようなやり方の方がユーザにとってわかりやすいと思います。

余談ですが、トランザクション分離レベルに関するフレームワークへの
要件って、全体の分離レベルを操作することよりも個々のトランザクション
で調整することの方が強く求められると思います。
なぜなら、前者はやるときは大抵DBの設定で一斉にやってしまうからです。
それで、「あるSQLだけダーティリードにしたい」って要件が開発途中とか
運用保守中に出てくるんですね。

Comment by koyak [ 2008-02-19 ]

もう一つ確認させていただきたいことがありました。

トランザクション分離レベルの指定はどうしましょう。。。
今はとりあえずReadCommitedで動くようにしています。

Transaction属性の引数に渡すものを少し変えて、
DaoSettingと同様にTransactionSettingを渡してもらって
設定するのはいかがでしょう?
(なければ例のごとくapp.configから探す)
(DaoSettingとは分けた方がいい気がします。
SQLに関するあれこれを設定することと
トランザクションをかけることは同じDB絡みでも別モノかと)

public interface ITransactionSetting
{
ITransactionContext TransactionContext

{ get; }
AbstractInterceptor TransactionInterceptor { get; }

// これもいらないかも?
ITransactionStateHandler TransactionStateHandler

{ get; }

void Setup(IDataSource dataSource);
}

Comment by koyak [ 2008-02-18 ]

ご意見ありがとうございます。>お二方

>App.config標準機能のDB接続文字列を指定する方法ではだめでしょうか?
こちらの指定方法のことを失念していました(^^;
やってみようと思います。

>> IDaoSetting
>IDaoSettingをプログラム上で別途指定するやり方も合った方が良いです。

これは自分でもコード書いてて「これだと自動生成しづらいか・・・?」と
ちょっと思ってました(^^;すいません。

とすると、IDaoSettingは

public interface IDaoSetting
{
IDataReaderFactory DataReaderFactory

{ get; }
ICommandFactory CommandFactory { get; }

IAnnotationReaderFactory AnnotationReaderFactory

{ get; }
IDaoMetaDataFactory DaoMetaDataFactory { get; }

AbstractInterceptor DaoInterceptor

{ get; }

void Setup(IDataSource dataSource);
}

こんな感じでしょうか。
Setupメソッドは以前杉本さんが挙げられたInitDaoMetaDataFactory
にあたるものです。
DaoInterceptorの設定もあるかもしれないので
このメソッド名にしています。
(これ入れるのならDaoMetaDataFactory、DaoIntercetor以外の
プロパティはいらないかもですね)

この辺は下手に自動設定するよりも
カスタマイズする人に書いてもらった方がいいかな、と。

このIDaoSettingをS2Dao属性に指定できるようにする、と。

内部でチェックする順序としては

S2Dao属性が指定されているか?
(どこにも指定がなければIDaoSettingを作らない)

S2Dao属性にIDaoSettingが指定されているか?
(指定されていればそれを使う)

app.configにIDaoSettingが指定されているか?
(指定されていればそれを使う)

どちらもなければ標準設定の
TypicalDaoSettingを使う

こんな感じでやってみます。

Comment by jflute [ 2008-02-18 ]

小谷さん、休日つぶしてお疲れです。

> IDaoSetting
IDaoSettingをプログラム上で別途指定するやり方も合った方が良いです。
なぜかというと、自動生成ツールなどでその指定を自動生成する場合に、
App.configだと生成できないからです。

以前の仕様のようにS2Dao属性の引数にIDaoSettingsを指定して、
App.configの指定は、その指定が無い場合のデフォルトってことでどうでしょう?
(InteceptorもIDaoSettingsで指定)

Comment by sugimotokazuya [ 2008-02-18 ]

お疲れ様です。

DB接続文字列とデータプロバイダの部分ですが
App.config標準機能のDB接続文字列を指定する方法ではだめでしょうか?
http://s2container.net.seasar.org/ja/db-appconfig.html#AppConfig

Comment by koyak [ 2008-02-18 ]

もう一つ。プロバイダの指定については
SQLServer,Oracle,DB2などの定番のものはクラスの形で
用意して、それを指定するという形でいいのではないかと
思っています。
(connectionTypeがOracleConnectionで他は
SqlXxxを使う、というのは実質ありえないと思うため)
独自プロバイダの指定を使う場合はDataProviderを継承した
クラスを作成し、app.configの<provider>に
名前空間付で指定という形にする、とか。

Comment by koyak [ 2008-02-18 ]

・app.configからデータソースの定義をできるようにできました。
・diconなしでトランザクション付でDaoInterceptorをかけられるようにできました。

以下のような仕様で実装しています。
ご意見等お願い致します。

[S2Dao]属性(クラス/メソッド)を付けるとDaoInerceptorがかかる。
 ・引数は無しor Type
 ・無しの場合はDaoInterceptorが適用される
 ・Typeが指定された場合はその型をInterceptorとして使おうとする。
[Transaction]については前に書いたものと同様。
○S2Daoで使用するクラスのカスタマイズはIDaoSettingを実装して行う
 (IDataReaderFactory,ICommandFactory,IDaoMetaDataFactory,
IAnnotationReaderFactoryをプロパティにもつ)
 ・DaoSettingの指定はapp.configにクラス名を記述して行う
 ・名前空間が書かれていなければ規定の名前空間から探す
 ・指定がなければBasicCommandFactoryなどが指定されてTypicalDaoSetting
  クラスが適用される

↓app.configの設定例
<quill>
<dataSources>
<dataSource>
<connectionString>Hoge</connectionString>
<provider>OleDb</provider>
</dataSource>
</dataSources>
<daoSetting>TypicalDaoSetting</daoSetting>
</quill>

上記仕様で特に問題がなければテストコードも書いていきたいと思います。

Comment by jflute [ 2008-02-15 ]

ありがとうございます。
特に問題はないかと思います。
(ソースはじっくり見れてないですが)

> 1.App.config上にあるデータソースの定義(未実装)
続けて、こちらお願いします。

Comment by koyak [ 2008-02-15 ]

違うファイルをあげてしまったので再アップ

Comment by koyak [ 2008-02-15 ]

下記のような仕様で実装してみたのですが
どう思われますか?
(変更したソースコードは添付ファイル(source.zip)を
ご参照下さい)

○トランザクション
[Transaction]属性で指定(クラス/メソッド)
引数は無し or Type
無しの場合はLocalRequireTxが適用される

Type型で使えるのは「AbstractQuillTransactionInterceptor」の
継承クラスのみ
(TransactionInterceptorをQuillContainerで管理して
使えるように拡張したもの)
※現時点ではLocalRequireTxに対応するInterceptorしか
 実装していない

○複数データソース対応
S2Containerに
AbstractSelectableDataSourceProxy
SelectableDataSourceProxyWithContainer

Quillに
SelectableDataSourceProxyWithDictionary

を追加(名前長・・・)

基本的な使い方はJava版のSelectableDataSourceProxyと同じ
~WithContainerの方はS2Container、
~WithDictionaryはIDictionaryを使ってDataSourceを管理する。

SelectableDataSourceProxyWithDictionaryの方は
IDataSourceSelectorというインターフェースをプロパティに
もっている。
特別にデータソースの切り替えロジックを入れる場合は
このインターフェースを実装してセットする。
(いつセットするかは使う人まかせ)

Quill上のデータソースを参照するクラスは基本的にこの
SelectableDataSourceProxyWithDictionaryを使う

QuillContainerがnewされるとSelectableDataSourceProxyWithDictionaryの
QuillContainerへの登録処理が行われる。

登録処理時、以下の優先度で
SelectableDataSourceProxyWithDictionary
にデータソースが登録される。

1.App.config上にあるデータソースの定義(未実装)
2.dicon上に名前が"DataSource"で登録されている
コンポーネント
3.diconからtypeof(IDataSource)で取得できる
コンポーネント

Quill.Example上ではトランザクションの開始→コミットの流れで
動くことは確認しています。
(データソース一個だけでですが)

Comment by koyak [ 2008-02-08 ]

添付ファイル→DataSourceManager.csです。
Shift-JISで書いてしまいました(^^;

Comment by koyak [ 2008-02-08 ]

複数データソース対応の案として。

データソースを管理するクラス(添付ファイル:DataSourceManager参照)を用意し、
Quill上ではDataSourceはこのクラスから取得するようにする。
(複数データソースかどうかは利用側は気にしない)

使用するデータソースはApp.settingに記述
起動時などにRegistDataSourceを呼び出して登録。

データソース選択ロジック(添付ファイル:IDataSourceSelector参照)は
App.settingなどに記述されていればインスタンスを生成して
起動時などにセットしておく。

余裕があれば以下のような基本的なものについてはあらかじめ用意しておく
・diconから取得(添付ファイル:S2ContaineDataSourceSelector参照)
・ラウンドロビン
・ランダム

Comment by sugimotokazuya [ 2008-02-05 ]

> これは、Quillの方向性の根本に関わるので明確にしておきたいのです。
Transaction属性はQuill単独の機能として、Aspect属性ではこれまでどおりS2Containerと連携もできますという形で良いと思います。

小谷さんのデータソースの指定方法の件ですが、Logicにトランザクションをかける場合は、どんな感じをそう指定していますか?

Comment by jflute [ 2008-02-05 ]

> これは、Quillの方向性の根本に関わるので明確にしておきたいのです。
このコメントは私(jflute)です。ログアウト状態で書いてしまいました...orz

Comment by Anonymous [ 2008-02-05 ]

> Transaction属性を使う場合はS2ContainerのTransactionには対応しなくていいのではないか。

これは、Quillの方向性の根本に関わるので明確にしておきたいのです。

上記の対応でよいというのは、
「QuillとS2Containerは基本的に併用して使うことは推奨しないことを意味する」
「併用してもいいが完全に別物として考えるべきである」
と考えてよろしいでしょうか?

例えば、S2DaoをQuill対応したとして、いわば2つのS2Dao
「S2Container管理のS2Dao」と「Quill管理のS2Dao」となり、
これらを実行する時のトランザクションの発行(&コネクションの管理)が
それぞれ別になると思います。

いや、これでもいいとは思うのですが、単に明確にしておきたいって話です。
そしてそれをユーザにはっきり言わないといけないと思います。
(正直ユーザがQuillの立ち位置を理解できてないのです)

> データソースは初めから複数データソースに対応しておけば後が楽(難しい部分なので)

これは単純にパワーの問題なので、小谷さんいけるかな!?

Comment by koyak [ 2008-02-05 ]

複数データソースの対応について
こんなイメージはいかがでしょうか?

データソースのConnectionStringなどの設定は基本的にApp.configに記述

○静的にデータソースを割り当てる
App.config上で
<DataSource>
(接続先とか)
<Target>.*Dao</Target>
</DataSource
というように正規表現アリでそのデータソースを使うDaoを指定する。
(コンポーネントの自動登録と同じようなイメージ)

○動的にデータソースを割り当てる
Quill上でCurrentDataSourceのようなものをstaticにもち、Quill,S2Daoはそれを使う。
App.config上に定義したデータソースを状況に応じて
CurrentDataSourceを設定するコーディングはユーザに行ってもらう。

(HogeDaoSettingはHogeDaoSettingでその他のカスタマイズ用に用意しておく)

Comment by koyak [ 2008-02-05 ]

Skypeでお話した内容のメモ
・Transaction属性を使う場合はS2ContainerのTransactionには対応
 しなくていいのではないか。
 (Aspect["コンポーネント名"]で対応できるため)

・データソースは初めから複数データソースに対応しておけば
 後が楽(難しい部分なので)。

Comment by koyak [ 2008-02-03 ]

小谷です。

まずはトランザクションの指定をできるように、ということで

1.TransactionAttribute([Transaction])でトランザクションを
 指定できる。

2.1が指定された場合、
2-a.diconにトランザクション系のコンポーネント (TransactionInterceptor)がある
 →S2Containerから取得してトランザクションを取り扱う
2-b.diconになければQuill側で拡張した同等の働きをする
 コンポーネントを作成し、それを使ってトランザクションを取り扱う。

という形で実装してみました。

確認はQuill.Exampleの方で行っています。

コードの方もできればご覧になっていただきたいのですが、
上記の仕様で実装したものをコミットしても
よろしいでしょうか?
(テストの追加はしていませんが、現状の単体テストは通ります。)

蛇足:
以前のコメントで書いたpartialは違うアセンブリをまたいでの
利用はできませんでした。
ヘルプにも書いてありました(^^;

Comment by jflute [ 2008-01-30 ]

Anonymousになってますが、杉本さんですよね?(^^

シンプルと柔軟性の狭間での調整になるかと思います。
(シンプルもとても大事ですし柔軟性もとても大事です)

Settings自体はしっかりインターフェースになっているので、
要はS2Dao属性の引数なしのデフォルトSettingsがどこかで
指定できたら良いのではないかと考えています。
(これは後実装でもいいかもですね)

これならば、内部構造も複雑にはならないし、
外部インターフェースもシンプルで、かつ、
いざってときの柔軟性もあるかなと。

その「デフォルトSettings」が設定ファイルなのか、
何かのClassにするのかは多いに検討の余地ありです。

Comment by Anonymous [ 2008-01-30 ]

jfluteさん

もし他に解決策や良い案があれば、私の案の原型が残ってなくても全然大丈夫ですので、
お願いしますm(_ _)m

jfluteさんの方が、現場の声を知っていると思いますので。

Comment by jflute [ 2008-01-29 ]

杉本さんコメントありがとうございます。

まあ、HogeDaoSettingsが全てのDaoアノテーションに指定ってのは、
ちょっとどうかなってところです。

DBFluteは自動生成なので全然問題ないですが、
「開発終盤でS2Daoのクラスを拡張せざるを得なくなった」という状況が
発生した場合に、一箇所指定じゃなく横断修正になるが引っかかります。
逆にそれなら引数なしの「[S2Dao]」は無しにして、かならずユーザには
S2Dao(typeof(HogeDaoSettings))]と指定してもらう方がアリかなとも思います。

横断修正自体はそんなに大変じゃないとは思うので致命的ではないですが、
ユーザの気持ち的に「えーなんでこんな仕様なの!?」と思われるのを心配しています。

> 小谷さんへ

「Step1. S2ContainerとS2Daoはそのままで本機能を実現する。」
だけでも着手できたらお願いしたいです。

なぜかというと、今のトランザクションを発行できない状態だと
Quillを積極利用することができないからです。
S2Container + Quill だったら、Quillを使う意味が半減するし、
Quillだけだとトランザクション発行できなくて使えないとなってしまうのです。

Comment by sugimotokazuya [ 2008-01-13 ]

遅くなってすいません。とりあえず、どういう考えだったかを書いておきます。

データプロバイダやS2Dao.NETのコンポーネントのカスタマイズはAbstractDaoSettingsを継承して1つクラスを用意します。

たとえば次のように。DB接続の設定が1つの場合はデータプロバイダの設定は不要。さらに標準のS2Dao.NETの構成の場合は、このようなクラスは必要なし。

public class HogeDaoSettings : AbstractDaoSettings
{
public HogeDaoSettings()

{ // App.configのデータプロバイダの設定名 this.ProviderInvariantName = "HogeConnection"; }

// このようなカスタマイズ用のメソッドがいろいろ用意されている
protected override void InitDaoMetaDataFactory()

{ // DaoMetaDataFactoryをカスタマイズ this.daoMetaDataFactory = new HogeMetaDataFactory(); }

}

これをTransaction属性やS2Dao属性に設定します。DB設定が1つだけの場合は引数なし。

// 複数のデータソースが存在する場合
[Transaction(typeof(HogeDaoSettings))]
public virtual void HogeHoge()

// 設定が1つだけの場合はこれだけ。
[Transaction)]
public virtual void HogeHoge()

// 複数のデータソースが存在する場合
[S2Dao(typeof(HogeDaoSettings))]
public interface IHogeDao

// 設定が1つだけの場合はこれだけ。
[S2Dao]
public interface IHogeDao

HogeDaoSettingsとかを作るのは面倒な感じですが、1つのデータソースにつき1つだけ用意すればいいので、ドキュメントをしっかり用意すれば、XMLの設定ファイルを書くより、受け入れられるんじゃないかと考えています。

Comment by jflute [ 2008-01-13 ]

> ・(U)ユーザ様にpartial interface IDataSourceというように
> コードを書いていただき、その中で使う実装クラスを指定してもらう。

Assemblyをまたがってpartialでできたっけ???
(自分昔やろうとしてできなかった記憶があったのですが...)

確かにそれができれば、ユーザ様の指定を確立することができますね。

Comment by koyak [ 2008-01-13 ]

すいません。上で自分が書いている内容って
パターン1とも違ってますね(^^;
Step1とStep2を同時に実装する、というイメージでお願いします。

Comment by koyak [ 2008-01-13 ]

小谷です。

パターン1に1票です。
S2Daoの機能を使うにあたってはQuill側は
dao/ado.diconで設定していたクラスの
Quillコンポーネント化をしやすくする仕組みを
提供する、という形に留めて方が
使う側(特にS2Dao使用経験のある人)としては
S2Daoのことだけ知っていればある程度までは大丈夫と
なるので学習コストが少なくて済むのではないかと思います。

dao/Ado.diconで設定していたクラスについては
Seasar,S2Dao側のInterfaceをpartial化し、
それを利用してもらう、というのはどうでしょう?

以下、
(U)=ユーザ様側で対応
(Q)=Quill側で対応
(S)=S2Container/S2Dao側で対応

まず
(S)S2Daoで使用するinterfaceをpublic partial interfaceに変更する。
その後に
 ○使用する実装クラスが基本的に1種類のinterfaceの場合(ICommandFactoryなど)
・(Q)Quill内に対応するpartial interfaceを用意する。
・(Q)下記のようにImplementation属性を定義
[Implementation(typeof(BasicCommandFactory))]
partial interface ICommandFactory
{
}

(Q)コンストラクタorメソッドインジェクションを使って
設定を行っているクラスはプロパティで設定できるように
拡張したクラスを用意する。

 ○使用する実装クラスの候補が複数あるinterfaceの場合(IDataSourceなど)
  ・(U)ユーザ様にpartial interface IDataSourceというように
   コードを書いていただき、その中で使う実装クラスを指定してもらう。

   (Q)DataSourceの場合はあらかじめ各DBMS用の設定をしてある
   IDataSource実装クラス(大体のDBMSはTxDataSourceを継承?)を
   Quill内に用意しておく(SQLServerDataSourceみたいに)。

   (U)以下のようなコードをどこかに書いてもらう
   [Implementation(typeof(SQLServerDataSource))]
   partial interface IDataSource
   {
   }

   (Q)ConnectionStringなどの文字列設定項目は
   public partial interface IConnectionString
   

{     string GetConnectionString();    }

   というようなinterfaceを新たにQuill側で用意し、
   (U)ユーザ側でIConnectionStringを実装
   (ベタに書くか、app.configなどを使うかはユーザの自由)、
   その後に
   (U)
[Implementation(typeof(ConnectionStringImpl))]
   partial interface IConnectionString
   {
   }

   といった形で実装してもらう(delegateを使うのもアリかも)。

あとは
(Q)「S2Dao使用版QuillInjector」をQuilInjectorを
継承するか何かして作成。
(Q)中でS2Daoで使用するクラスに対してデフォルトでInjectするようにする。

-----------------------------------------------------------

普通にS2Daoを使うのよりも手間がかかってしまいそうな
気がしなくもないのですが・・・。
一つの案として提案させていただきます。

Comment by jflute [ 2008-01-11 ]

ひとまず、既出の情報で機能仕様をまとめてみました。
ひとまず意識合わせとしましょう。

要確認事項があります。
杉本さんはどういうイメージでしたか?

  • * * * * * * * *
    Quill Transaction
  • * * * * * * * *

[機能要件]
Quillだけでトランザクションを発行させて、
S2Daoと連携できるようにする。

[機能概要]
QuillコンポーネントのメソッドにTransaction属性を付けることで
そのメソッド呼び出しがトランザクションとなる。

[関連機能要件]
A. S2DaoのQuillコンポーネント化。
B. DB接続情報はDiconではなくApp.configから取得する。

これらは本機能を実現するための最終的な実現方法の要素となる。

[関連機能概要]
<A>
DaoインターセプタにS2Dao属性を付けることで、Quill管理のDaoになる。
利用するときは通常のQuillコンポーネントと同様に取得できる。

要確認
S2ContainerのトランザクションでQuillのS2Daoが動作するようにするか?
実現としては、S2Containerのコネクション管理が存在すれば利用する形でOK。
しかもニーズとしては結構ありそうである。
設定で連動と切り離しを選択できてもいいかもしれない。

要確認
今までdao.diconに設定していたクラスたちをどこでどのように指定するか?
これらは拡張ポイントとなっていたため、どこかしらで指定できる必要があるが、
1箇所指定の設定なので、S2Dao属性の引数は適さないかも。。。
また、Ado.diconにて定義されていたクラスはどうするか?

<B>
App.configに定義されたDB接続情報を利用してコネクション管理をQuill自身が行う。
S2Containerが存在していなくてもDBアクセスリソースを保持することが可能になる。
複数DBや分離レベルの指定をTransaction属性の引数でできるようにする。
S2Containerのコネクション管理が存在する場合はそちらのものを利用する。

要確認
S2Containerのコネクション管理が存在する場合は、どのように連携するのか?
S2Container優先でそちらを使うようにするのか?完全に分離するのか?
(「A」での要確認事項と関連)

[実装考察]
段階的な実装を行うべきかと思われる。
ただし、既出の要確認事項次第でそのStepは変わる。

パターン1:
S2Containerと連動

Step1. S2ContainerとS2Daoはそのままで本機能を実現する。
Step2. 関連機能の「A」を実現する。
Step3. 関連機能の「B」を実現する。

<Step1>
まずトランザクション開始を実現する。
このとき、Transaction属性は「引数なし」のみをサポート。
実際にはS2Containerの管理するコネクションを利用する。
S2Dao側は今までと何も変わらずトランザクション内で実行される。

<Step2>
S2DaoをQuillコンポーネント化し、dao.diconもなしとする。
但し、この時点ではまだコネクションはS2Containerからの取得に限定する。

<Step3>
Quillがコネクションを管理し、S2Containerレスとする。
Transaction属性の「引数あり」の方もサポート。
S2Containerのコネクション管理が存在しない場合に最終形の仕様で動作する。
(S2Containerのコネクション利用は「引数なし」に限定)

パターン2:
S2Containerと切り離し

Step1. パターン1におけるStep1,3を実現する。
Step2. パターン1におけるStep2を実現する。

Comment by jflute [ 2008-01-10 ]

なるほど、了解です。
ちょとこちらもそれを考えてました。
1月下旬と2月上旬にちょっと時間取れそうです。

杉本さんには概念設計と内部設計をやってもらって
実装と単体テストはこちらで吸収できればいいかなと。
細かくタスクを分けて、他の人とも手分けできるように
なれば一番いいかなとも思います。

Comment by sugimotokazuya [ 2008-01-10 ]

依存しなくはないのですが、あまり分けても工数は減らない感じです。
S2Dao.NETの方より、データソースをどう扱うかがポイントなので。
あとプライベートが忙しくなってしまったので、時間かかるかもしれません。
jfluteさん、どうですか?実装してみませんか?

Comment by jflute [ 2008-01-09 ]

DaoのQuill化とQuillでのトランザクション制御はどうしても依存しますか?

もし、そうでないなら、
まずQuillでのトランザクション制御だけやって、後でDaoのQuill化をやる、
というような段階リリースもありかなと思いました。

既にQuillを使ってやろうとしているプロジェクトもあり、
(Quillも公開されて結構経ちますし)
アプリのアーキテクチャがガラリと変わってしまう修正だけ
先に実現できるのであればと考えました。

  1. DaoのQuill化はアプリのアーキテクチャ的には影響薄だと思うので...
Comment by sugimotokazuya [ 2007-12-17 ]

> これも、もうAdo.diconを利用しないイメージですかね。
> もしや本当に、完全Diconレスになる!?

そうです。Quillで完全にdiconファイルを無くすための機能です。

Comment by jflute [ 2007-12-16 ]

> いえ、Aspect属性でS2ContainerのDaoInterceptorを指定していた所をS2Dao属性にします。
> Daoインターフェースに付けます。

ああ、なるほど了解です。

> S2DaoをQuillで属性を用意して特別扱いしてしまいます。
> S2Daoはどうしてもコンポーネントをカスタマイズする必要があるので、
> Quillの機能では構築が無理なのです。

まあ、仕方ないですね。
対応されたら、DBFluteのDaoインターフェースもS2Dao属性を付けるようにします。
すると、Dao自体もDiconに設定する必要がなくなる!?!?

> 引数なしの場合はアプリケーション構成ファイルのDB設定の1つ目が自動で使われます。
> 複数のDB接続やS2Daoのコンポーネント、トランザクションモードをデフォルトから変更したい場合は属性に引数を渡します。

これも、もうAdo.diconを利用しないイメージですかね。
もしや本当に、完全Diconレスになる!?

Comment by sugimotokazuya [ 2007-12-16 ]

> これって、S2Daoを使ったDBアクセスの場合は、
> Transactionを開始したいメソッドに、Transaction属性以外に
> S2Dao属性をつけるってことですか?
いえ、Aspect属性でS2ContainerのDaoInterceptorを指定していた所をS2Dao属性にします。
Daoインターフェースに付けます。

S2DaoをQuillで属性を用意して特別扱いしてしまいます。
S2Daoはどうしてもコンポーネントをカスタマイズする必要があるので、
Quillの機能では構築が無理なのです。

Comment by jflute [ 2007-12-16 ]

ありがとうございます。

> S2Daoを使いたい場合にはS2Dao属性をつけます。
これって、S2Daoを使ったDBアクセスの場合は、
Transactionを開始したいメソッドに、Transaction属性以外に
S2Dao属性をつけるってことですか?

> 引数にはIDaoContextの実装クラスのTypeを渡せます。(IDaoSettingsの方が良いかな?)
> (引数の型をType<IDaoContext>みたいに定義できたら良いけど無理っぽい。)
TypeクラスがGenericじゃないからダメなんですよねぇ...これ自分も悔しい思いしました。

Comment by sugimotokazuya [ 2007-12-16 ]

トランザクションを行うにはTransaction属性をつけます。
S2Daoを使いたい場合にはS2Dao属性をつけます。
これらの属性は引数なしかType型を引数として渡せます。

引数なしの場合はアプリケーション構成ファイルのDB設定の1つ目が自動で使われます。
複数のDB接続やS2Daoのコンポーネント、トランザクションモードをデフォルトから変更したい場合は属性に引数を渡します。

引数にはIDaoContextの実装クラスのTypeを渡せます。(IDaoSettingsの方が良いかな?)
(引数の型をType<IDaoContext>みたいに定義できたら良いけど無理っぽい。)
デフォルトから変えたい場合はAbstractDaoContextを継承します。
そのクラスでDB接続やS2Daoのコンポーネント、トランザクションモードのカスタマイズができます。

引数で指定されたDaoContextは始めて使われるときにインスタンス化されQuillに登録されます。

Diconのような設定ファイルを使わない方針なので、こんな感じしかないかなと思っています。

Comment by jflute [ 2007-12-14 ]

昨日、口頭で伺った「やり方を悩んでる」っていうの、
詳細を書いて頂ければ、一緒に悩んで議論できるので、
書いてくれるとうれしいです。>リーダ

Comment by jflute [ 2007-12-10 ]

おお、これは何気に無茶苦茶欲しい機能ですね。
(Quill中心で開発をした場合など)

Generated at Mon Dec 15 06:32:56 JST 2025 using Jira 10.6.1#10060001-sha1:a6461e220f274b29ced7ac9295492f2465fe5ef5.