문제

배경:

우리 팀은 체크 아웃에서 바로 우리의 코드 컴파일 및 단위 테스트가 성공적으로 실행되도록하기 위해 최선을 다하고 있습니다. 이를 용이하게하고 Nhibernate 매핑 중 일부를 테스트하기 위해 프로덕션 SQL Server 2005 데이터베이스의 미러 인 저장소에 SQLITE DB를 추가했습니다. 우리는 MBUNIT3 (Gallio의 일부), System.Data.sqlite 및 Nhibernate의 최신 버전을 사용하고 있습니다.

문제:

SQL Server 2005에 대한 문제없이 실행 되었음에도 불구하고 다음 단위 테스트가 SQLITE에서 작동하지 않는다는 것을 발견했습니다.

    [Test]
    [Rollback]
    public void CompleteCanPersistNode()
    {
        // returns a Configuration for either SQLite or SQL Server 2005 depending on how the project is configured.
        Configuration config = GetDbConfig(); 

        ISessionFactory sessionFactory = config.BuildSessionFactory();
        ISession session = sessionFactory.OpenSession();

        Node node = new Node();
        node.Name = "Test Node";
        node.PhysicalNodeType = session.Get<NodeType>(1);

        // SQLite fails with the exception below after the next line called.
        node.NodeLocation = session.Get<NodeLocation>(2);

        session.Save(node);
        session.Flush();

        Assert.AreNotEqual(-1, node.NodeID);
        Assert.IsNotNull(session.Get<Node>(node.NodeID));
    }

내가 얻는 예외 (sqlite와 함께 일할 때만)는 다음과 같습니다.

NHibernate.ADOException: cannot open connection --->
System.Data.SQLite.SQLiteException:
  The database file is locked database is locked
    at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
    at System.Data.SQLite.SQLiteDataReader.NextResult()
    at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
    at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
    at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
    at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock)
    at System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel)
    at System.Data.SQLite.SQLiteConnection.BeginTransaction()
    at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
    at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
    at System.Data.SQLite.SQLiteConnection.Open()
    at NHibernate.Connection.DriverConnectionProvider.GetConnection()
    at NHibernate.Impl.SessionFactoryImpl.OpenConnection()
    --- End of inner exception stack trace ---
    at NHibernate.Impl.SessionFactoryImpl.OpenConnection()
    at NHibernate.AdoNet.ConnectionManager.GetConnection()
    at NHibernate.AdoNet.AbstractBatcher.Prepare(IDbCommand cmd)
    at NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
    at NHibernate.Loader.Loader.GetResultSet(IDbCommand st, Boolean autoDiscoverTypes, Boolean callable, RowSelection selection, ISessionImplementor session)
    at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
    at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
    at NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, String optionalEntityName, Object optionalIdentifier, IEntityPersister persister)
    at NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId)
    at NHibernate.Loader.Entity.AbstractEntityLoader.Load(Object id, Object optionalObject, ISessionImplementor session)
    at NHibernate.Persister.Entity.AbstractEntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session)
    at NHibernate.Event.Default.DefaultLoadEventListener.LoadFromDatasource(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.DoLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent event, LoadType loadType)
    at NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType)
    at NHibernate.Impl.SessionImpl.Get(String entityName, Object id)
    at NHibernate.Impl.SessionImpl.Get(Type entityClass, Object id)
    at NHibernate.Impl.SessionImpl.Get[T](Object id)
D:\dev\598\Code\test\unit\DataAccess.Test\NHibernatePersistenceTests.cs

SQLITE가 사용되고 [롤백] 속성이 지정되지 않으면 테스트도 성공적으로 완료됩니다.

의문:

MBUNIT3가 [롤백]에 사용하는 TransactionScope 구현 또는 SQLITE 엔진의 제한 사항이 있습니까?

테스트가 실행될 때마다 데이터베이스에 영향을 미치지 않도록 SQLITE에 대해이 단위 테스트를 작성하고 SQLITE에 대해 작업하는 방법이 있습니까?

도움이 되었습니까?

해결책

누락되지 않았는지 확인하십시오 connection.release_mode=on_close sqlite nhibernate 구성에서. (참조 문서)

BTW : 항상 당신의 처분 ISession 그리고 ISessionFactory.

다른 팁

이것은 귀하의 질문에 대한 실제 답변이 아니라 문제를 해결하기위한 해결책 일 것입니다.

통합 테스트에 SQL Lite의 메모리 구현을 사용합니다. 각 테스트 전에 스키마를 빌드하고 데이터베이스를 채우십시오. 스키마 생성 및 초기 데이터 충전은 메모리 내 데이터베이스이기 때문에 실제로 빠르게 발생합니다 (테스트 당 0.01 초 미만).

물리적 데이터베이스를 사용하는 이유는 무엇입니까?

편집 : 위의 질문에 대한 답변에 대한 응답 :

1.) SQL Server 2005에서 스키마와 데이터를 직접 마이그레이션하고 소스 제어에서 지속되기를 원합니다.

  • 데이터베이스 스키마가있는 파일과 소스 컨트롤에서 샘플 데이터를 생성하는 파일 또는 스크립트를 저장하는 것이 좋습니다. SQL Server Studion Management Express를 사용하여 파일을 생성 할 수 있고 Nhibernate 매핑에서 파일을 생성하거나 SQL 비교와 같은 도구를 사용할 수 있으며 필요할 때 다른 솔루션을 찾을 수 있습니다. 일반 텍스트 파일은 버전 제어 시스템에 더 쉽게 저장된 다음 바이너리 데이터베이스 파일을 완료합니다.

2.) 메모리 내 SQLITE 엔진에 대해이 어려움을 해결할 수 있도록 다른 일을합니까?

  • 각 테스트 전에 데이터베이스를 재현 할 수 있으므로 문제를 해결할 수 있습니다. 테스트중인 데이터베이스는 각 테스트가 실행되기 전에 예상되는 상태에 있습니다. 그 이점은 트랜잭션을 롤백 할 필요가 없지만 Memory Sqllite에서 비슷한 테스트를 실행했으며 Aspected로 작동했습니다.

도랑 [롤백] 및 사용 ndbunit. 나는이 정확한 시나리오에 이것을 직접 사용하고 있으며 그것은 훌륭하게 작동하고 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top