Я использую NHibernate для своих данных, и какое-то время я не использовал SQLite для тестов локальной интеграции. Я использовал файл, но подумал, что выберу опцию: memory :. Когда я запускаю какой-либо из интеграционных тестов, кажется, что база данных создана (NHibernate выплевывает sql создания таблицы), но взаимодействие с базой данных вызывает ошибку.
Кто-нибудь получил NHibernate, работающий с базой данных в памяти? Это вообще возможно? Строка подключения, которую я использую, такова:
Data Source=:memory:;Version=3;New=True





Просто дикая догадка, но является ли вывод sql NHibernate с помощью команды, не поддерживаемой sqlite?
Кроме того, что произойдет, если вы используете файл вместо памяти? (System.IO.Path.GetTempFileName () будет работать, я думаю ...)
База данных памяти SQLite существует только до тех пор, пока соединение с ней остается открытым. Чтобы использовать его в модульных тестах с NHibernate:
1. Откройте ISession в начале вашего теста (возможно, с помощью метода [SetUp]) .
2. Используйте соединение из этого сеанса в вызове SchemaExport.
3. Используйте тот же сеанс в своих тестах.
4. Закройте сеанс в конце вашего теста (возможно, с помощью метода [TearDown]).
ага, в этом есть смысл! Даст ему шанс
также взгляните на этот пример реализации DriverConnectionProvider: notepad2.wordpress.com/2008/05/19/…
К вашему сведению, у меня возникли проблемы с поддержанием соединения с NHibernate после вызова Flush. Нашел ответ на bit.ly/23CRTT
Мы используем SQLite в памяти для всех наших тестов базы данных. Мы используем одно соединение ADO для тестов, которое повторно используется для всех сеансов NH, открытых одним и тем же тестом.
Это также позволяет запускать тесты с несколькими включенными сеансами. SessionFactory также создается один раз для всех тестов, потому что чтение файлов сопоставления занимает довольно много времени.
Редактировать
Начиная с System.Data.Sqlite 1.0.82 (или Sqlite 3.7.13), существует Общий кеш, который позволяет нескольким соединениям совместно использовать одни и те же данные, также для Базы данных в памяти. Это позволяет создавать базу данных в памяти в одном соединении и использовать ее в другом. (Пока не пробовал, но по идее должно работать):
file::memory:?cache=sharedИспользуете ли вы перегрузку Open Session для обеспечения соединения или у вас есть более хитрый способ использования того же соединения?
Я использую OpenSession (IDbConnection) и получаю соединение один раз из sessionFactory.ConnectionProvider.GetConnection (). Я, вероятно, мог бы реализовать свой собственный ConnectionProvider, тогда это было бы только вопросом конфигурации. Но до сих пор у меня не было на это времени.
Я делаю это с помощью Rhino Commons. Если вы не хотите использовать Rhino Commons, вы можете изучить источник и посмотреть, как он это делает. Единственная проблема, с которой я столкнулся, заключается в том, что SQLite не поддерживает вложенные транзакции. Это заставило меня изменить свой код для поддержки интеграционного тестирования. Интеграционное тестирование с базой данных в памяти настолько круто, что я решил, что это справедливый компромисс.
У меня было много проблем с базой данных памяти SQLite. Итак, теперь мы используем SQLite для работы с файлами на RAM-диске.
Это могло быть решением в прошлом, но в новых версиях sqlite нет необходимости, поскольку они предоставляют возможность использовать общую область базы данных. Это намного проще в использовании и требует меньше инструментов. Для актуального решения см. Следующий отвечать
У меня были аналогичные проблемы, которые продолжались даже после открытия ISession, как указано выше, и добавления «Pooling = True; Max Pool Size = 1» в строку подключения. Это помогло, но у меня все еще были случаи, когда соединение закрывалось во время теста (обычно сразу после совершения транзакции).
Что в итоге сработало для меня, так это установка для свойства connection.release_mode значения on_close в моей конфигурации SessionFactory.
Моя конфигурация в файле 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>
Надеюсь, это поможет!
Пробовал это решение, но у него есть серьезный недостаток при использовании HiLo Id-Generators. При вставке большого количества новых записей в базу данных это решение ломается. Причина в том, что nhibernate может получить только одно соединение, но может потребоваться дополнительное, чтобы получить следующий HiLo-Range из БД. В более новых версиях sqlite лучшим решением является использование решения, которое определяет значение связь.
Я смог использовать базу данных SQLite в памяти и избежать необходимости перестраивать схему для каждого теста с помощью SQLite поддержка 'Shared Cache', который позволяет разделять базу данных в памяти между соединениями.
Я сделал в AssemblyInitialize (использую MSTest) следующее:
Настройте NHibernate (свободно) для использования SQLite со следующей строкой подключения:
FullUri=file:memorydb.db?mode=memory&cache=shared
Используйте эту конфигурацию для создания объекта hbm2ddl.SchemaExport и выполнения его в отдельном соединении (но снова с той же самой строкой соединения).
Перед запуском каждого теста создается новый сеанс, и тест запускается в транзакции, которая откатывается в конце.
Вот пример тестового кода уровня сборки:
[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();
}
}
Я допускаю, что управление ресурсами может быть улучшено, но это, в конце концов, модульные тесты (предлагаемые улучшения приветствуются!).
Идеальный! Это лучшее решение, другие решения часто основаны на более старых версиях sqlite, которые не обеспечивали возможность использования именованных ("file: xyz.db? Mode = memory") баз данных sqlite в памяти с активным пулом соединений.
Обратите внимание, что в более поздних версиях sqlite вам может потребоваться сделать что-то вроде этого для вашей строки подключения (и это работает с Loquacious API): config.DataBaseIntegration(c => { /*...*/ c.ConnectionString = "DataSource=file:memdb1?mode=memory&cache=shared" }) - см. stackoverflow.com/a/12324672/489116 и комментарии, а также форумы.devart.com/viewtopic.php?t=26312#p119530.
Просто хочу поблагодарить Decates. Пытался решить эту проблему уже пару месяцев, и все, что мне нужно было сделать, это добавить
FullUri=file:memorydb.db?mode=memory&cache=shared
в строку подключения в моем конфигурационном файле nhibernate. Также используя только NHibernate с * .hbm.xml, а не FNH, и мне вообще не нужно было изменять мой код!
У меня такая же ошибка, когда я забыл импортировать пакет SQLite Nuget.
Через какое-то время есть другое решение. См. Дополнительный блок в моем ответе.