FluentNHibernateマッピング設定をテストする統合テストを作成しようとしています。テストの基本的な考え方は、いくつかのデータを挿入してから読み取って、挿入されたデータが読み取ったデータと一致することを確認することです。テストを実行するたびにテストデータをデータベースに追加したくないので、トランザクションを使用してデータを挿入しようとしていますが、そのトランザクションはまだ開いていますが、コミットされていないデータを(別のセッションを使用して) 。プランは、アサーションが作成されると、データの挿入前後でトランザクションをロールバックし、テストを実行する前と同じ状態にデータベースを残します。残念ながら、しかし、私はデータを読み取ろうとした時点で、次のエラーを取得しています:IsolationLevel.ReadUncommittedを使用した場合のタイムアウトSqlException
NHibernate.Exceptions.GenericADOException : could not load an entity: [CQRSTutorial.DAL.EventDescriptor#51ff4d15-ddbc-4157-8652-a7a10177a6e3][SQL: SELECT eventdescr0_.Id as Id1_2_0_, eventdescr0_.EventType as EventT2_2_0_, eventdescr0_.Data as Data3_2_0_ FROM Events eventdescr0_ WHERE eventdescr0_.Id=?] ----> System.Data.SqlClient.SqlException : Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
次のように私は、特にこの問題を強調するために、テストを作成しました:
[TestFixture, Category(TestConstants.Integration)]
public class TimeoutExpiredTest
{
private ISession _writeSession;
public static ISessionFactory CreateSessionFactory(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
{
var msSqlConfiguration = MsSqlConfiguration
.MsSql2012
.IsolationLevel(isolationLevel)
.ConnectionString(x => x.FromConnectionStringWithKey("CQRSTutorial"));
var cfg = new CustomAutomappingConfiguration();
return Fluently
.Configure()
.Database(msSqlConfiguration)
.Mappings(m =>
{
m.AutoMappings.Add(
AutoMap.AssemblyOf<EventDescriptor>(cfg)
.UseOverridesFromAssemblyOf<EventDescriptorMapping>());
})
.BuildSessionFactory();
}
[SetUp]
public void SetUp()
{
_writeSession = CreateSessionFactory().OpenSession();
_writeSession.BeginTransaction();
}
[Test]
public void InsertAndReadTabOpened()
{
var objectToStoreInDbTemporarily = GetObjectToStoreInDbTemporarily();
_writeSession.SaveOrUpdate(objectToStoreInDbTemporarily);
_writeSession.Flush(); // the data needs to go to the database (even if only temporarily), rather than just staying in an NHibernate cache.
var readSession = CreateSessionFactory(IsolationLevel.ReadUncommitted).OpenSession();
var retrievedEventDescriptor = readSession.Get<EventDescriptor>(objectToStoreInDbTemporarily.Id); // this line throws the exception after 30 seconds.
// If previous line worked, I could then assert inserted values match retrieved values at this point.
}
[TearDown]
public void TearDown()
{
_writeSession.Transaction?.Rollback();
}
public class CustomAutomappingConfiguration : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
return type.Name == typeof(EventDescriptor).Name; // we're only mapping this class for now.
}
}
私は簡潔さのためにオブジェクトを作成するコードを削除しました。元のテストは目的でした。問題のオブジェクトに対してNHibernateマッピングを正しく定義する必要がありました。しかし、最初のテストでは、テストが実行されるたびに新しい行が挿入されていました。
SQLプロファイラを見ると、読み取り側に問題があるようです。読み取りセッションは、IsolationLevel.ReadUncommittedではなくIsolationLevel.ReadCommittedを使用しています。読み取りセッションがテストで指定されたIsolationLevelを使用しない理由は何ですか?
'BeginTransaction()'の呼び出しが 'ReadUncommitted'分離レベルのトランザクションを確実に開いていることを確認しましたか?設定を作成するときに指定されていますが、チェックする価値はあると思います。さらに、 'uncommitted'読み取りレベルでSQL Serverでクエリを実行して、SQL Serverが期待どおりに動作するかどうかを確認しましたか? –
ありがとう、David。私はSQLプロファイラをチェックインしましたが、write-sessonのトランザクションオープンを見ることができます。これはReadCommittedとして開きますが、それは問題ありません。しかし、Read-Session(ReadUncommittedとして設定しようとした)が、プロファイラーにReadCommittedとして表示されているため、タイムアウトになります。また、このテストのデバッグ中に、トランザクション分離レベルReadUncommittedを使用している間に、SQL Server Management Studioでコミットされていないデータを確認することができました。ですから、今調べるべき唯一の理由は、read-sessionが、指定されたReadUncommittedの代わりにReadCommittedとしてオープンしている理由です。 –
テスト設定からこの行を変更してください: '_writeSession.BeginTransaction();'を '_writeSession.BeginTransaction(IsolationLevel.ReadUncommitted);に変更して、それがどのような効果を持っているかを見てください。構成レベルで分離レベルを設定しても、目的の効果が得られない可能性があります。 –