Quillでトランザクション
Quillでトランザクションをするためにはトランザクションをかけたいメソッドに[Transaction]属性をつけます
またApp.config内のdataSourcesタグのデータソースの設定で
を指定します。
<dataSources> <!-- Oracle --> <dataSource name="Oracle"> <provider>Oracle</provider> <connectionString>...</connectionString> <class>Seasar.Extension.Tx.Impl.TxDataSourceImpl</class> </dataSource> </dataSources>
このようにしておいてトランザクションをかけたいメソッドに[Transaction]属性
をつけると、このメソッドから例外が発生したときにRollbackされます
[Transaction] public void RegisterData() { try { // データ登録ロジック } catch(Exception ex) { throw; } }
複数のデータソースでトランザクションをかける場合はデータソース毎にカスタムトランザクション設定クラスの実装が必要です。
public class OracleTransactionSetting : AbstractTransactionSetting { protected override void SetupTransaction(IDataSource dataSource) { // TransactionContext _transactionContext = new TransactionContext(); TransactionContext txContext = (TransactionContext)_transactionContext; txContext.DataSouce = dataSource; txContext.IsolationLevel = IsolationLevel.ReadCommitted; // TransactionContextを使用するデータソースにも設定 Type dataSourceType = dataSource.GetType(); if (typeof(SelectableDataSourceProxyWithDictionary).IsAssignableFrom( dataSourceType)) { ((SelectableDataSourceProxyWithDictionary)dataSource) .SetTransactionContext(txContext); } else if (typeof(TxDataSource).IsAssignableFrom(dataSourceType)) { ((TxDataSource)dataSource).Context = txContext; } // TransactionInterceptor LocalRequiredTxHandler handler = new LocalRequiredTxHandler(); handler.Context = txContext; _transactionInterceptor = new TransactionInterceptor(handler); ((TransactionInterceptor)_transactionInterceptor).TransactionStateHandler = txContext; } public override String DataSourceName { get { return "Oracle"; } // App.config内のデータソース設定の<dataSource name="Oracle"> の記述に合わせる } }
トランザクションをかけたい箇所に[Transaction]属性をつけます
[Transaction(typeof(OracleTransactionSetting))] public void RegisterData() { try { // データ登録ロジック } catch(Exception ex) { throw; } }
[seasar-dotnet:1210] Quill で複数データソースでのトランザクション制御に失敗するで議論されていますが、複数のデータソースがある場合トランザクションに失敗するようです。
public class OracleTransactionSetting : AbstractTransactionSetting { protected override void SetupTransaction(IDataSource dataSource) { // TransactionContext _transactionContext = TransactionContextCreator.GetTransactionContext(dataSource); TransactionContext txContext = (TransactionContext)_transactionContext; // TransactionContextを使用するデータソースにも設定 Type dataSourceType = dataSource.GetType(); if (typeof(SelectableDataSourceProxyWithDictionary).IsAssignableFrom( dataSourceType)) { ((SelectableDataSourceProxyWithDictionary)dataSource) .SetTransactionContext(txContext); } else if (typeof(TxDataSource).IsAssignableFrom(dataSourceType)) { ((TxDataSource)dataSource).Context = txContext; } // TransactionInterceptor LocalRequiredTxHandler handler = new LocalRequiredTxHandler(); handler.Context = txContext; _transactionInterceptor = new TransactionInterceptor(handler); ((TransactionInterceptor)_transactionInterceptor).TransactionStateHandler = txContext; } public override String DataSourceName { get { return "Oracle"; } } } public class PostgreSQLTransactionSetting : AbstractTransactionSetting { protected override void SetupTransaction(IDataSource dataSource) { // TransactionContext _transactionContext = TransactionContextCreator.GetTransactionContext(dataSource); TransactionContext txContext = (TransactionContext)_transactionContext; // TransactionContextを使用するデータソースにも設定 Type dataSourceType = dataSource.GetType(); if (typeof(SelectableDataSourceProxyWithDictionary).IsAssignableFrom( dataSourceType)) { ((SelectableDataSourceProxyWithDictionary)dataSource) .SetTransactionContext(txContext); } else if (typeof(TxDataSource).IsAssignableFrom(dataSourceType)) { ((TxDataSource)dataSource).Context = txContext; } // TransactionInterceptor LocalRequiredTxHandler handler = new LocalRequiredTxHandler(); handler.Context = txContext; _transactionInterceptor = new TransactionInterceptor(handler); ((TransactionInterceptor)_transactionInterceptor).TransactionStateHandler = txContext; } public override String DataSourceName { get { return "PostgreSQL"; } } } public static class TransactionContextCreator { private static TransactionContext _transactionContext = null; public static ITransactionContext GetTransactionContext(IDataSource dataSource) { if (_transactionContext == null) { _transactionContext = new TransactionContext(); _transactionContext.DataSouce = dataSource; _transactionContext.IsolationLevel = IsolationLevel.ReadCommitted; } return _transactionContext; } }
このようにすると良いらしいです
Quillで複数データベースにアクセス
Quillで複数のデータベースにアクセスするための設定に手間取ったので
その結果を書いておきます。
複数のデータベース(データソース)に接続するために必要なものは
1.App.config内のdataSourcesタグにデータソースの設定を記述
Quillで簡単DI+AOP - S2Container.NET にあるように設定ファイル(App.config)の
「quill」セクション内の「dataSources」タグ内に各データソースの設定を書きます。
<dataSources> <!-- Oracle --> <dataSource name="Oracle"> <provider>Oracle</provider> <connectionString>...</connectionString> <class>Seasar.Extension.ADO.Impl.DataSourceImpl</class> </dataSource> <!-- PostgreSQL --> <dataSource name="PostgreSQL"> <provider>PostgreSQL</provider> <connectionString>...</connectionString> <class>Seasar.Extension.ADO.Impl.DataSourceImpl</class> </dataSource> </dataSources>
上の設定内容の中の
Seasar.Extension.ADO.IDataSourceに対する実装クラス名を指定する必要があり
データソース毎に別のクラスを指定しないといけません。
Seasar.Extension.ADO.Impl.DataSourceImplやSeasar.Extension.Tx.Impl.TxDataSourceImplの継承クラスをデータソース毎に作成し、コンストラクタを記述します。
koyakさんのご指摘によりカスタムデータソース実装クラスは不要であることがわかりました。
koyakさんありがとうございます。
2.データソース毎にSeasar.Quill.Dao.IDaoSetting実装クラスを作成する
public class OracleDaoSetting : Seasar.Quill.Dao.Impl.AbstractDaoSetting { protected override void SetupDao(IDataSource dataSource) { BasicCommandFactory commandFacoty = new BasicCommandFactory(); BasicDataReaderFactory dataReaderFactory = new BasicDataReaderFactory(commandFacoty); FieldAnnotationReaderFactory annotationReaderFactory = new FieldAnnotationReaderFactory(); _daoMetaDataFactory = new DaoMetaDataFactoryImpl( dataSource, commandFacoty, annotationReaderFactory, dataReaderFactory); _daoInterceptor = new S2DaoInterceptor(_daoMetaDataFactory); } public override String DataSourceName { get { return "Oracle"; } // App.config内のデータソース設定の<dataSource name="Oracle"> の記述に合わせる } }
3.DaoクラスにS2Dao属性を使用し、カスタム設定を適用させる
[S2Dao(typeof(OracleDaoSetting))] [Implementation] [Bean(typeof(HogeDto))] public interface IOracleDao { int insert(HogeDto dto); }
このような設定で複数のデータソースへのアクセスができました。
QuillでSQLiteを使ってみる
QuillでSQLiteをアクセスしようと思い調べてみたが
Seasar.NETでは対応されているもののQuillでは未対応らしい。
ただ独自のプロバイダクラスを作成することで何とかなるようだ
http://s2container.net.seasar.org/ja/quill.html#nodicon_assembly
Seasarメーリングリストで問い合わせたら、すぐに回答いただきました、感謝です。
以下MLからの引用です。
1. http://sqlite.phxsoftware.com/ からSQLite.NETをダウンロードしてインストールする
2. Seasar.Extension.ADO.DataProviderを継承したクラスを作成する。
3. 2.で作成したクラスのコンストラクタの中でConnectionType 、CommandType、ParameterType、DataAdapterTypeプロパティにSQLite用のクラス名を名前空間付きで指定する。
public class SQLite: Seasar.Extension.ADO.DataProvider { public SQLite() { ConnectionType = "System.Data.SQLite.SQLiteConnection"; CommandType = "System.Data.SQLite.SQLiteCommand"; ParameterType = "System.Data.SQLite.SQLiteParameter"; DataAdapterType = "System.Data.SQLite.SQLiteDataAdapter"; } }
4. 設定ファイルのproviderセクションに2.で作成したクラス名を名前空間付きで指定する
5. 設定ファイルのassemblyセクションにSystem.Data.SQLiteを指定する
<configuration> <quill> <assemblys> <assembly>Seasar.Quill</assembly> <assembly>Seasar.Dxo</assembly> <assembly>Seasar.DynamicProxy</assembly> <!-- SQLite.NET を使用する場合に必要です。 --> <assembly>System.Data.SQLite</assembly> </assemblys> <dataSources> <!-- SQLite --> <dataSource name="sqlite"> <provider>xxx.xxxx.SQLite</provider> <connectionString>"Data Source=test.db;"</connectionString> <class>Seasar.Extension.Tx.Impl.TxDataSource</class> </dataSource> </dataSources> </quill> </configuration>
TestDriven.NETでSetupが動かない
S2Unit.NETを使って単体テストしてますが、VS2005のアドインでTestDriven.NET
を使用しています。
[SetUp, S2] public void SetUpSeasarTest() { SingletonS2ContainerFactory.Init(); this.Container = SingletonS2ContainerFactory.Container; } [Test, S2] public void コンテナが取得できるはず() { Assert.IsNotNull(this.Container, "コンテナが取得できるはず"); }
このようにしてテストを行っていたのですがthis.Containerがnullのままで
インスタンスを取得してくれません。原因はSetUpSeasarTestを通らないのが原
因です。
調べた結果このサイトに回答がありました
http://blog.davebouwman.net/2008/08/05/TroubleRunningMbUnitTestsWithTestDrivennetOnVista64.aspx
TestDriven.NetはインストーラではMbUnitを使用する設定をしてくれないようです。
- MbUnitをインストールする http://www.mbunit.com/
- TestDriven.NETにMbUnitを使用するためのレジストリを登録する
下のレジストリを登録すればよいようです。
Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\MutantDesign\TestDriven.NET\TestRunners\MbUnit] @="10" "AssemblyPath"="C:\\Program Files\\MbUnit\bin\\MbUnit.AddIn.dll" "TypeName"="MbUnit.AddIn.MbUnitTestRunner" "TargetFrameworkAssemblyName_Reference"="MbUnit.Framework" "Application"="C:\\Program Files\\MbUnit\bin\\MbUnit.GUI.exe"