我使用NHibernate进行数据访问,最近我一直在使用SQLite进行本地集成测试。我一直使用文件,但是我想尝试使用`:memory:`选项。当我启动任何集成测试时,数据库似乎已经被创建(NHibernate输出了表格创建SQL),但是与数据库交互会导致错误。
有人曾经成功地使用内存数据库与NHibernate配合吗?这是否可能?我使用的连接字符串如下:
Data Source=:memory:;Version=3;New=True
我使用NHibernate进行数据访问,最近我一直在使用SQLite进行本地集成测试。我一直使用文件,但是我想尝试使用`:memory:`选项。当我启动任何集成测试时,数据库似乎已经被创建(NHibernate输出了表格创建SQL),但是与数据库交互会导致错误。
有人曾经成功地使用内存数据库与NHibernate配合吗?这是否可能?我使用的连接字符串如下:
Data Source=:memory:;Version=3;New=True
SQLite内存数据库只在连接保持打开状态时存在。为了在NHibernate的单元测试中使用它,需要按照以下步骤:
1. 在测试开始时(可能是[SetUp]方法中),打开一个ISession。
2. 在SchemaExport调用中使用该会话的连接。
3. 在测试中使用同一个会话。
4. 在测试结束时(可能是[TearDown]方法中),关闭会话。
Configure NHibernate (Fluently) to use SQLite with the following connection string:
FullUri=file:memorydb.db?mode=memory&cache=shared
Use that configuration to create a hbm2ddl.SchemaExport object, and execute it on a separate connection (but with that same connection string again).
[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();
}
}
我承认资源管理可能需要改进,但这毕竟只是单元测试(欢迎提出改进建议!)。
config.DataBaseIntegration(c => { /*...*/ c.ConnectionString = "DataSource=file:memdb1?mode=memory&cache=shared" })
-- 请参见 https://dev59.com/a2fWa4cB1Zd3GeqPdx5n#12324672 和评论,以及 https://forums.devart.com/viewtopic.php?t=26312#p119530。 - S'pht'Kr编辑
自System.Data.Sqlite 1.0.82(或Sqlite 3.7.13)以来,有一个共享缓存,允许多个连接共享相同的数据,也适用于内存数据库。这允许在一个连接中创建内存数据库,并在另一个连接中使用它。(我还没有尝试过,但理论上应该可以):
file::memory:?cache=shared
我曾经遇到过类似的问题,即使按照上面所述的方法打开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>
我使用SQLite内存数据库遇到了很多问题。现在我们正在使用在ramdrive磁盘上处理文件的SQLite。
我遇到了同样的错误,当我忘记导入SQLite Nuget包时。
只是一个猜测,NHibernate输出的SQL是否使用了SQLite不支持的命令?
另外,如果使用文件而不是内存会发生什么?(我认为System.IO.Path.GetTempFileName()可以工作...)
我正在使用Rhino Commons。如果你不想使用Rhino Commons,你可以研究源代码看它是如何实现的。我遇到的唯一问题是SQLite不支持嵌套事务。这迫使我改变了我的代码以支持集成测试。使用内存数据库进行集成测试非常棒,我认为这是一个公平的妥协。
只是想感谢decates。我已经试图解决这个问题几个月了,而我所需要做的就是添加
FullUri=file:memorydb.db?mode=memory&cache=shared
在我的NHibernate配置文件中添加连接字符串。同时,只使用*.hbm.xml的NHibernate,而不是FNH,并且几乎没有修改我的代码!