diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpUnitTestSqliteConnection.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpUnitTestSqliteConnection.cs new file mode 100644 index 0000000000..f33f31ded3 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpUnitTestSqliteConnection.cs @@ -0,0 +1,52 @@ +using System.Threading; +using Microsoft.Data.Sqlite; +using Volo.Abp.Threading; + +namespace Volo.Abp.EntityFrameworkCore.Sqlite; + +/// +/// This class is for unit testing purposes. +/// It prevents exceptions in concurrent testing because Sqlite is not thread-safe. +/// +public class AbpUnitTestSqliteConnection : SqliteConnection +{ + public AbpUnitTestSqliteConnection(string connectionString) + : base(connectionString) + { + } + + public override SqliteCommand CreateCommand() + { + return new AbpSqliteCommand + { + Connection = this, + CommandTimeout = DefaultTimeout, + Transaction = Transaction + }; + } +} + +internal class AbpSqliteCommand : SqliteCommand +{ + private readonly static SemaphoreSlim SyncSemaphore = new SemaphoreSlim(1, 1); + + public override SqliteConnection? Connection + { + get => base.Connection; + set + { + using (SyncSemaphore.Lock()) + { + base.Connection = value; + } + } + } + + protected override void Dispose(bool disposing) + { + using (SyncSemaphore.Lock()) + { + base.Dispose(disposing); + } + } +}