我在我的 ASP.NET 6 應用程式中使用 NHibernate。出于集成測驗的目的,我使用 SQLite 記憶體資料庫。
這是用于集成測驗的 NHibernate 配置的樣子:
_configuration = new Configuration();
_configuration.DataBaseIntegration(db =>
{
db.Driver<SQLite20Driver>();
db.Dialect<MySqliteDialect>();
db.ConnectionProvider<SQLiteInMemoryConnectionProvider>();
db.ConnectionString = "Data Source=:memory:;Version=3;New=True;DateTimeKind=Utc;DateTimeFormatString=yyyy-MM-dd HH:mm:ss.FFFFFFF";
db.LogSqlInConsole = true;
db.ConnectionReleaseMode = ConnectionReleaseMode.OnClose;
db.HqlToSqlSubstitutions = "true=1;false=0";
db.SchemaAction = SchemaAutoAction.Validate;
});
var mapping = new ModelMapper();
mapping.AddMappings(typeof(ApplicationUserMapping).Assembly.GetTypes());
// other mappings..
var mappingDocument = mapping.CompileMappingForAllExplicitlyAddedEntities();
_configuration.AddMapping(mappingDocument);
_configuration.LinqToHqlGeneratorsRegistry<DefaultLinqToHqlGeneratorsRegistry>();
var exp = new SchemaExport(_configuration);
exp.Execute(true, true, false);
_sessionFactory = _configuration.BuildSessionFactory();
我有SettingsService一個具有以下方法的類:
public async Task<IList<Setting>> GetAll()
{
using var session = _factory.OpenSession();
var settings = await session.QueryOver<Setting>().ListAsync();
return settings;
}
現在,當我從一個簡單的 NUnit 測驗中呼叫這個方法時:
[Test]
public async Task GetAll()
{
var settings = await new SettingsService(_sessionFactory).GetAll();
}
我收到一個錯誤:
NHibernate.Exceptions.GenericADOException : could not execute query
[ SELECT this_.Id as id1_0_0_, this_.Name as name2_0_0_, this_.Value as value3_0_0_ FROM Settings this_ ]
[SQL: SELECT this_.Id as id1_0_0_, this_.Name as name2_0_0_, this_.Value as value3_0_0_ FROM Settings this_]
----> System.Data.SQLite.SQLiteException : SQL logic error
no such table: Settings
整個測驗的輸出如下所示:
PRAGMA foreign_keys = OFF
drop table if exists Settings
// other tables drops...
PRAGMA foreign_keys = ON
create table Settings (
Id BLOB not null,
Name TEXT not null unique,
Value TEXT not null,
primary key (Id)
)
// other tables creation...
NHibernate: SELECT this_.Id as id1_0_0_, this_.Name as name2_0_0_, this_.Value as value3_0_0_ FROM Settings this_
NHibernate.Exceptions.GenericADOException : could not execute query
[ SELECT this_.Id as id1_0_0_, this_.Name as name2_0_0_, this_.Value as value3_0_0_ FROM Settings this_ ]
[SQL: SELECT this_.Id as id1_0_0_, this_.Name as name2_0_0_, this_.Value as value3_0_0_ FROM Settings this_]
----> System.Data.SQLite.SQLiteException : SQL logic error
no such table: Settings
Data:
actual-sql-query: SELECT this_.Id as id1_0_0_, this_.Name as name2_0_0_, this_.Value as value3_0_0_ FROM Settings this_
at NHibernate.Loader.Loader.DoListAsync(ISessionImplementor session, QueryParameters queryParameters, IResultTransformer forcedResultTransformer, QueryCacheResultBuilder queryCacheResultBuilder, CancellationToken cancellationToken)
at NHibernate.Loader.Loader.ListIgnoreQueryCacheAsync(ISessionImplementor session, QueryParameters queryParameters, CancellationToken cancellationToken)
at NHibernate.Loader.Criteria.CriteriaLoaderExtensions.LoadAllToListAsync[T](IList`1 loaders, ISessionImplementor session, CancellationToken cancellationToken)
at NHibernate.Impl.SessionImpl.ListAsync[T](CriteriaImpl criteria, CancellationToken cancellationToken)
at NHibernate.Impl.SessionImpl.ListAsync[T](CriteriaImpl criteria, CancellationToken cancellationToken)
這樣就可以看到Settings表已經創建好了。
如果我將GetAll()方法的實作更改為不是異步的,即不是使用ListAsync(),而是List()函式:
public IList<Setting> GetAll()
{
using var session = _factory.OpenSession();
var settings = session.QueryOver<Setting>().List();
return settings;
}
測驗通過(當然,在洗掉async,Task并await從中洗掉之后)。
我見過這個問題,但在我的情況下,唯一的區別是使用 NHibernate 的異步與非異步方法。我ISessionFactory在集成測驗的初始化代碼和SettingsService.
知道這里發生了什么嗎?
uj5u.com熱心網友回復:
根據 SQLite檔案:
一旦資料庫連接關閉,記憶體中的資料庫就不再存在。每個 :memory: 資料庫都與其他資料庫不同。因此,打開兩個檔案名為“:memory:”的資料庫連接將創建兩個獨立的記憶體資料庫。
默認情況下,每次打開會話時都會創建新連接。所以這個錯誤是默認設定的預期行為。
但是您使用了一些自定義連接提供程式SQLiteInMemoryConnectionProvider,這些提供程式可以重用一次打開的連接。所以我會說問題出在內部SQLiteInMemoryConnectionProvider——它沒有為異步代碼做好準備。
確保您的連接提供程式同時實作GetConnection和GetConnectionAsync方法。就像是:
public override DbConnection GetConnection()
{
return _connection ??= base.GetConnection();
}
public override async Task<DbConnection> GetConnectionAsync(CancellationToken cancellationToken)
{
return _connection ??= await base.GetConnectionAsync(cancellationToken);
}
或者它可能使用ThreadStaticfield 來存盤connection,它應該使用AsyncLocal:
private readonly AsyncLocal<DbConnection> _connection = new AsyncLocal<DbConnection>();
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/387511.html
上一篇:如何使用建構式實體化一個類?
