Pergunta

Eu uso o NHibernate para o meu dataacess, e por algum tempo não estou usando SQLite para testes de integração local. Eu tenho usado um arquivo, mas eu pensei que eu faria o: memória: opção. Quando eu o fogo até qualquer um dos testes de integração, o banco de dados parece ser criado (NHibernate cospe o sql criação da tabela), mas interfacting com o banco de dados causa um erro.

Alguém cada trabalho NHibernate obtido com uma base de dados de memória? Será que é mesmo possível? A seqüência de conexão que estou usando é o seguinte:

Data Source=:memory:;Version=3;New=True
Foi útil?

Solução

banco de dados de memória Um SQLite só existe enquanto a conexão com ela permanece em aberto. Para usá-lo em testes de unidade com NHibernate:
1. Abra um ISession no início do seu teste (talvez em um [Configuração] método).
2. Use a conexão dessa sessão na sua chamada SchemaExport.
3. Use essa mesma sessão em seus testes.
4. Feche a sessão no final do seu teste (talvez em um [TearDown] Método).

Outras dicas

Eu era capaz de usar um banco de dados SQLite em memória e evitar ter que reconstruir o esquema para cada teste usando suporte href="http://www.sqlite.org/inmemorydb.html#sharedmemdb"> 'cache compartilhado', que permite que um banco de dados in-memory para ser compartilhado através de conexões.

Eu fiz o seguinte no AssemblyInitialize (estou usando MSTest):

  • Configurar o NHibernate (fluente) para usar SQLite com a seguinte seqüência de conexão:

    FullUri=file:memorydb.db?mode=memory&cache=shared
    
  • Use essa configuração para criar um hbm2ddl. SchemaExport objeto, e executá-lo em uma conexão separada (mas com a mesma seqüência de conexão de novo).

  • Deixe a conexão aberta, e referenciado por um campo estático, até AssemblyCleanup , em que ponto ele está fechado e descartado. Isso ocorre porque SQLite precisa de pelo menos uma ligação activa a ser realizada no banco de dados in-memory para saber que ainda é necessário e evitar arrumando a casa.

Antes de cada teste é executado, uma nova sessão é criada, e as execuções de teste em uma transação que é revertida no final.

Aqui está um exemplo do código de teste de nível de assembly:

[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;
        }
    }
}

E uma classe base para cada classe de teste de unidade / dispositivo elétrico:

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();
    }
}

A gestão de recursos pode melhorar, eu admito, mas estes são testes de unidade após todos (melhorias sugeridas bem-vindos!).

Estamos usando SQLite na memória para todos os nossos testes de banco de dados. Estamos usando uma única conexão ADO para os testes que é reutilizada para todas as sessões NH abertas pelo mesmo teste.

  1. Antes de cada teste: criar conexão
  2. Criar esquema nesta conexão
  3. Executar teste. A mesma conexão é usada para todas as sessões
  4. Após o teste: estreita ligação

Isso também permite a execução de testes com várias sessões incluídas. O SessionFactory também é criado de uma vez por todos os testes, porque a leitura dos arquivos de mapeamento leva algum tempo.


Editar

O uso do cache compartilhado

Desde System.Data.SQLite 1.0.82 (ou Sqlite 3.7.13 ), há uma cache compartilhado, que permite várias ligações para compartilhar os mesmos dados, também para bases de dados na memória . Isso permite a criação do in-memory-base de dados em uma conexão, e usá-lo em outro. (Eu não tentei ainda, mas, em teoria, isso deve funcionar):

  • Altere a seqüência de conexão para file::memory:?cache=shared
  • Abrir uma conexão e criar o esquema
  • Mantenha este abrir conexão até o final do teste
  • Let NH criar outras ligações (comportamento normal) durante o teste.

Eu tive problemas semelhantes que durou até depois de abrir o ISession como dito acima, e adicionando "Pooling = true; Max Pool Size = 1" para a minha string de conexão. Isso ajudou, mas eu ainda tinha alguns casos onde a conexão iria fechar durante um teste (geralmente para a direita após cometer uma transação).

O que finalmente funcionou para mim foi a definição da propriedade "connection.release_mode" para "ON_CLOSE" na minha configuração SessionFactory.

A minha configuração no arquivo app.config agora olhar gosta deste:

  <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>

Espero que ajude!

Apenas um palpite, mas é a saída sql por NHibernate usando um comando não suportado pelo SQLite?

Além disso, o que acontece se você usar um arquivo em vez de memória? (System.IO.Path.GetTempFileName () iria funcionar eu acho ...)

Estou fazendo isso com Rhino Commons . Se você não quiser usar Rhino Commons você pode estudar a fonte sei como ele faz isso. O único problema que tive é que SQLite não suporta transações aninhadas. Isto obrigou-me a mudar o meu código para testes de integração apoio. testes de integração com banco de dados em memória é tão incrível, decidi que era um compromisso justo.

Eu tinha um monte de problemas com a base de dados de memória SQLite. Portanto, agora estamos usando SQLite trabalhar com arquivos em um disco ramdrive.

Só quero decates agradecimento. Tentado resolver isso por um par de meses e agora tudo o que eu tinha a fazer era adicionar

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

para a seqüência de conexão no meu arquivo de configuração nhibernate. Também usando apenas NHibernate com * .hbm.xml e não FNH e realmente não tem que modificar meu código em tudo!

Eu tenho o mesmo erro, quando eu esqueci de importar o pacote SQLite Nuget.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top