33

私は自分のデータアクセスに NHibernate を使用していますが、しばらくの間、ローカル統合テストに SQLite を使用していません。私はファイルを使用してきましたが、:memory: オプションを削除すると思いました。統合テストのいずれかを起動すると、データベースが作成されたように見えますが (NHibernate はテーブル作成 SQL を吐き出します)、データベースとやり取りするとエラーが発生します。

NHibernate をインメモリ データベースで動作させた人はいますか? それは可能ですか?私が使用している接続文字列は次のとおりです。

Data Source=:memory:;Version=3;New=True
4

9 に答える 9

41

SQLite メモリ データベースは、それへの接続が開いている間だけ存在します。NHibernate を使用した単体テストで使用するには:
1. テストの開始時に (おそらく [SetUp] メソッドで) ISession を開きます。
2. そのセッションからの接続を SchemaExport 呼び出しで使用します。
3. テストで同じセッションを使用します。
4. テストの最後に ([TearDown] メソッドで) セッションを閉じます。

于 2008-10-10T23:54:10.180 に答える
21

SQLite のインメモリ データベースを使用して、SQLite の'Shared Cache' のサポートを使用することで、テストごとにスキーマを再構築する必要がなくなりました。これにより、インメモリ データベースを接続間で共有できます。

AssemblyInitializeで次のことを行いました(MSTest を使用しています)。

  • 次の接続文字列で SQLite を使用するように NHibernate (Fluently) を構成します。

    FullUri=file:memorydb.db?mode=memory&cache=shared
    
  • その構成を使用して、hbm2ddl を作成します。SchemaExportオブジェクトを作成し、別の接続で実行します (ただし、同じ接続文字列を使用します)。

  • AssemblyCleanupまで、その接続を開いたままにし、静的フィールドによって参照されます。その時点で、接続は閉じられて破棄されます。これは、SQLite がまだ必要であることを認識し、片付けを避けるために、少なくとも 1 つのアクティブな接続をインメモリ データベースに保持する必要があるためです。

各テストが実行される前に、新しいセッションが作成され、最後にロールバックされるトランザクションでテストが実行されます。

アセンブリ レベルのテスト コードの例を次に示します。

[TestClass]
public static class SampleAssemblySetup
{
    private const string ConnectionString = "FullUri=file:memorydb.db?mode=memory&cache=shared";
    private static SQLiteConnection _connection;

    [AssemblyInitialize]
    public static void AssemblyInit(TestContext context)
    {
        var configuration = Fluently.Configure()
                                       .Database(SQLiteConfiguration.Standard.ConnectionString(ConnectionString))
                                       .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load("MyMappingsAssembly")))
                                       .ExposeConfiguration(x => x.SetProperty("current_session_context_class", "call"))
                                       .BuildConfiguration();

        // Create the schema in the database
        // Because it's an in-memory database, we hold this connection open until all the tests are finished
        var schemaExport = new SchemaExport(configuration);
        _connection = new SQLiteConnection(ConnectionString);
        _connection.Open();
        schemaExport.Execute(false, true, false, _connection, null);
    }

    [AssemblyCleanup]
    public static void AssemblyTearDown()
    {
        if (_connection != null)
        {
            _connection.Dispose();
            _connection = null;
        }
    }
}

そして、各単体テスト クラス/フィクスチャの基本クラス:

public class TestBase
{
    [TestInitialize]
    public virtual void Initialize()
    {
        NHibernateBootstrapper.InitializeSession();
        var transaction = SessionFactory.Current.GetCurrentSession().BeginTransaction();
    }

    [TestCleanup]
    public virtual void Cleanup()
    {
        var currentSession = SessionFactory.Current.GetCurrentSession();
        if (currentSession.Transaction != null)
        {
            currentSession.Transaction.Rollback();
            currentSession.Close();
        }

        NHibernateBootstrapper.CleanupSession();
    }
}

リソース管理が改善される可能性があることは認めますが、これらは結局のところ単体テストです (改善の提案を歓迎します!)。

于 2013-03-22T15:36:24.717 に答える
9

すべてのデータベース テストでメモリ内の SQLite を使用しています。同じテストによって開かれたすべての NH セッションで再利用されるテストに単一の ADO 接続を使用しています。

  1. すべてのテストの前に: 接続を作成します
  2. この接続でスキーマを作成
  3. テストを実行します。すべてのセッションで同じ接続が使用されます
  4. テスト後: 接続を閉じる

これにより、複数のセッションを含むテストを実行することもできます。マッピング ファイルの読み取りにはかなりの時間がかかるため、SessionFactory もすべてのテストに対して 1 回作成されます。


編集

共有キャッシュの使用

System.Data.Sqlite 1.0.82 (またはSqlite 3.7.13 ) 以降、共有キャッシュがあり、複数の接続が同じデータを共有できるようになりました。また、インメモリ データベースでも使用できます。これにより、1 つの接続でメモリ内データベースを作成し、別の接続で使用することができます。(私はまだ試していませんが、理論的にはこれでうまくいくはずです):

  • 接続文字列を次のように変更しますfile::memory:?cache=shared
  • 接続を開いてスキーマを作成する
  • テストが終了するまでこの接続を開いたままにしてください
  • テスト中に NH に他の接続を作成させます (通常の動作)。
于 2008-10-13T08:09:42.113 に答える
8

上記のように ISession を開き、接続文字列に「Pooling=True;Max Pool Size=1」を追加した後も同様の問題が発生しました。それは役に立ちましたが、テスト中に接続が閉じられるケースがまだいくつかありました (通常はトランザクションをコミットした直後)。

最終的にうまくいったのは、SessionFactory構成でプロパティ「connection.release_mode」を「on_close」に設定することでした。

app.config ファイルの構成は次のようになります。

  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <reflection-optimizer use="true" />
    <session-factory>
      <property name="connection.connection_string_name">testSqlLiteDB</property>
      <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.release_mode">on_close</property>
      <property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
      <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
      <property name="query.substitutions">true=1;false=0</property>
    </session-factory>
  </hibernate-configuration>

それが役に立てば幸い!

于 2010-12-21T16:51:01.463 に答える
1

私はSQLiteメモリデータベースに関する多くの問題を抱えていました。そのため、現在、RAMドライブディスク上のファイルを処理するSQLiteを使用しています。

于 2009-01-29T16:13:45.843 に答える
0

ただの大げさな推測ですが、SQLiteでサポートされていないコマンドを使用したNHibernateによるSQL出力はありますか?

また、メモリの代わりにファイルを使用するとどうなりますか?(System.IO.Path.GetTempFileName()は機能すると思います...)

于 2008-10-10T16:13:51.810 に答える
0

decates に感謝したいだけです。これを数か月間解決しようとしてきましたが、追加するだけで済みました

FullUri=file:memorydb.db?mode=memory&cache=shared

nhibernate 構成ファイルの接続文字列に。また、FNH ではなく *.hbm.xml で NHibernate のみを使用しているため、コードを変更する必要はまったくありませんでした。

于 2013-06-09T17:01:31.150 に答える
0

Rhino Commonsでやっています。Rhino Commons を使用したくない場合は、ソースを調べて、それがどのように機能するかを確認してください。私が経験した唯一の問題は、SQLite がネストされたトランザクションをサポートしていないことです。これにより、統合テストをサポートするためにコードを変更する必要がありました。インメモリ データベースとの統合テストは非常に優れているため、これはかなりの妥協点であると判断しました。

于 2008-10-22T03:23:20.687 に答える