mirror of https://github.com/abpframework/abp.git
28 changed files with 563 additions and 4 deletions
@ -0,0 +1,23 @@ |
|||
using System; |
|||
using Volo.Abp.MemoryDb; |
|||
using Volo.Abp.MemoryDb.DependencyInjection; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection |
|||
{ |
|||
public static class AbpMemoryDbServiceCollectionExtensions |
|||
{ |
|||
public static IServiceCollection AddMemoryDbContext<TMemoryDbContext>(this IServiceCollection services, Action<IMemoryDbContextRegistrationOptionsBuilder> optionsBuilder = null) |
|||
where TMemoryDbContext : MemoryDbContext |
|||
{ |
|||
var options = new MemoryDbContextRegistrationOptions(); |
|||
optionsBuilder?.Invoke(options); |
|||
|
|||
services.AddSingleton<TMemoryDbContext>(); |
|||
|
|||
new MemoryDbRepositoryRegistrar(options) |
|||
.AddRepositories(services, typeof(TMemoryDbContext)); |
|||
|
|||
return services; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.MemoryDb</AssemblyName> |
|||
<PackageId>Volo.Abp.MemoryDb</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp\Volo.Abp.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,9 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories.MemoryDb |
|||
{ |
|||
public interface IMemoryDatabase |
|||
{ |
|||
List<TEntity> Collection<TEntity>(); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories.MemoryDb |
|||
{ |
|||
public interface IMemoryDbRepository<TEntity> : IMemoryDbRepository<TEntity, Guid>, IQueryableRepository<TEntity> |
|||
where TEntity : class, IEntity<Guid> |
|||
{ |
|||
|
|||
} |
|||
|
|||
public interface IMemoryDbRepository<TEntity, TPrimaryKey> : IQueryableRepository<TEntity, TPrimaryKey> |
|||
where TEntity : class, IEntity<TPrimaryKey> |
|||
{ |
|||
IMemoryDatabase Database { get; } |
|||
|
|||
List<TEntity> Collection { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories.MemoryDb |
|||
{ |
|||
public class MemoryDatabase : IMemoryDatabase |
|||
{ |
|||
private readonly ConcurrentDictionary<Type, object> _sets; |
|||
|
|||
private readonly object _syncObj = new object(); |
|||
|
|||
public MemoryDatabase() |
|||
{ |
|||
_sets = new ConcurrentDictionary<Type, object>(); |
|||
} |
|||
|
|||
public List<TEntity> Collection<TEntity>() |
|||
{ |
|||
return _sets.GetOrAdd(typeof(TEntity), _ => new List<TEntity>()) as List<TEntity>; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System.Collections.Concurrent; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories.MemoryDb |
|||
{ |
|||
public static class MemoryDatabaseManager |
|||
{ |
|||
private static ConcurrentDictionary<string, IMemoryDatabase> _databases; |
|||
|
|||
static MemoryDatabaseManager() |
|||
{ |
|||
_databases = new ConcurrentDictionary<string, IMemoryDatabase>(); |
|||
} |
|||
|
|||
public static IMemoryDatabase Get(string databaseName) |
|||
{ |
|||
return _databases.GetOrAdd(databaseName, _ => new MemoryDatabase()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Linq.Expressions; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.MemoryDb; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories.MemoryDb |
|||
{ |
|||
public class MemoryDbRepository<TMemoryDbContext, TEntity> : MemoryDbRepository<TMemoryDbContext, TEntity, Guid>, IMemoryDbRepository<TEntity> |
|||
where TMemoryDbContext : MemoryDbContext |
|||
where TEntity : class, IEntity<Guid> |
|||
{ |
|||
public MemoryDbRepository(IMemoryDatabaseProvider<TMemoryDbContext> databaseProvider) |
|||
: base(databaseProvider) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public class MemoryDbRepository<TMemoryDbContext, TEntity, TPrimaryKey> : QueryableRepositoryBase<TEntity, TPrimaryKey>, IMemoryDbRepository<TEntity, TPrimaryKey> |
|||
where TMemoryDbContext : MemoryDbContext |
|||
where TEntity : class, IEntity<TPrimaryKey> |
|||
{ |
|||
public virtual List<TEntity> Collection => Database.Collection<TEntity>(); |
|||
|
|||
public virtual IMemoryDatabase Database => DatabaseProvider.GetDatabase(); |
|||
|
|||
protected IMemoryDatabaseProvider<TMemoryDbContext> DatabaseProvider { get; } |
|||
|
|||
public MemoryDbRepository(IMemoryDatabaseProvider<TMemoryDbContext> databaseProvider) |
|||
{ |
|||
DatabaseProvider = databaseProvider; |
|||
} |
|||
|
|||
public override TEntity Insert(TEntity entity, bool autoSave = false) |
|||
{ |
|||
Collection.Add(entity); |
|||
return entity; |
|||
} |
|||
|
|||
public override TEntity Update(TEntity entity) |
|||
{ |
|||
return entity; |
|||
} |
|||
|
|||
public override void Delete(TEntity entity) |
|||
{ |
|||
Collection.Remove(entity); |
|||
} |
|||
|
|||
protected override IQueryable<TEntity> GetQueryable() |
|||
{ |
|||
return Collection.AsQueryable(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Domain.Repositories.MemoryDb; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories |
|||
{ |
|||
public static class MemoryDbCoreRepositoryExtensions |
|||
{ |
|||
public static IMemoryDatabase GetDatabase<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository) |
|||
where TEntity : class, IEntity<TPrimaryKey> |
|||
{ |
|||
return repository.ToMemoryDbRepository().Database; |
|||
} |
|||
|
|||
public static List<TEntity> GetCollection<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository) |
|||
where TEntity : class, IEntity<TPrimaryKey> |
|||
{ |
|||
return repository.ToMemoryDbRepository().Collection; |
|||
} |
|||
|
|||
public static IMemoryDbRepository<TEntity, TPrimaryKey> ToMemoryDbRepository<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository) |
|||
where TEntity : class, IEntity<TPrimaryKey> |
|||
{ |
|||
var memoryDbRepository = repository as IMemoryDbRepository<TEntity, TPrimaryKey>; |
|||
if (memoryDbRepository == null) |
|||
{ |
|||
throw new ArgumentException("Given repository does not implement " + typeof(IMemoryDbRepository<TEntity, TPrimaryKey>).AssemblyQualifiedName, nameof(repository)); |
|||
} |
|||
|
|||
return memoryDbRepository; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Uow.MemoryDb; |
|||
|
|||
namespace Volo.Abp.MemoryDb |
|||
{ |
|||
public class AbpMemoryDbModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.TryAddTransient(typeof(IMemoryDatabaseProvider<>), typeof(UnitOfWorkMemoryDatabaseProvider<>)); |
|||
services.AddAssemblyOf<AbpMemoryDbModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.Data; |
|||
|
|||
namespace Volo.Abp.MemoryDb.DependencyInjection |
|||
{ |
|||
public interface IMemoryDbContextRegistrationOptionsBuilder : ICommonDbContextRegistrationOptionsBuilder |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.Data; |
|||
|
|||
namespace Volo.Abp.MemoryDb.DependencyInjection |
|||
{ |
|||
public class MemoryDbContextRegistrationOptions : CommonDbContextRegistrationOptions, IMemoryDbContextRegistrationOptionsBuilder |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.Domain.Repositories.MemoryDb; |
|||
|
|||
namespace Volo.Abp.MemoryDb.DependencyInjection |
|||
{ |
|||
public class MemoryDbRepositoryRegistrar : RepositoryRegistrarBase<MemoryDbContextRegistrationOptions> |
|||
{ |
|||
public MemoryDbRepositoryRegistrar(MemoryDbContextRegistrationOptions options) |
|||
: base(options) |
|||
{ |
|||
} |
|||
|
|||
protected override IEnumerable<Type> GetEntityTypes(Type dbContextType) |
|||
{ |
|||
var memoryDbContext = (MemoryDbContext)Activator.CreateInstance(dbContextType); |
|||
return memoryDbContext.GetEntityTypes(); |
|||
} |
|||
|
|||
protected override Type GetRepositoryTypeForDefaultPk(Type dbContextType, Type entityType) |
|||
{ |
|||
return typeof(MemoryDbRepository<,>).MakeGenericType(dbContextType, entityType); |
|||
} |
|||
|
|||
protected override Type GetRepositoryType(Type dbContextType, Type entityType, Type primaryKeyType) |
|||
{ |
|||
return typeof(MemoryDbRepository<,,>).MakeGenericType(dbContextType, entityType, primaryKeyType); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.Domain.Repositories.MemoryDb; |
|||
|
|||
namespace Volo.Abp.MemoryDb |
|||
{ |
|||
public interface IMemoryDatabaseProvider<TMemoryDbContext> |
|||
where TMemoryDbContext : MemoryDbContext |
|||
{ |
|||
TMemoryDbContext DbContext { get; } |
|||
|
|||
IMemoryDatabase GetDatabase(); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.MemoryDb |
|||
{ |
|||
public abstract class MemoryDbContext |
|||
{ |
|||
private static readonly Type[] EmptyTypeList = new Type[0]; |
|||
|
|||
public virtual IReadOnlyList<Type> GetEntityTypes() |
|||
{ |
|||
return EmptyTypeList; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using Volo.Abp.Domain.Repositories.MemoryDb; |
|||
|
|||
namespace Volo.Abp.Uow.MemoryDb |
|||
{ |
|||
public class MemoryDbDatabaseApi: IDatabaseApi |
|||
{ |
|||
public IMemoryDatabase Database { get; } |
|||
|
|||
public MemoryDbDatabaseApi(IMemoryDatabase database) |
|||
{ |
|||
Database = database; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.Domain.Repositories.MemoryDb; |
|||
using Volo.Abp.MemoryDb; |
|||
|
|||
namespace Volo.Abp.Uow.MemoryDb |
|||
{ |
|||
public class UnitOfWorkMemoryDatabaseProvider<TMemoryDbContext> : IMemoryDatabaseProvider<TMemoryDbContext> |
|||
where TMemoryDbContext : MemoryDbContext |
|||
{ |
|||
public TMemoryDbContext DbContext { get; } |
|||
|
|||
private readonly IUnitOfWorkManager _unitOfWorkManager; |
|||
private readonly IConnectionStringResolver _connectionStringResolver; |
|||
|
|||
public UnitOfWorkMemoryDatabaseProvider( |
|||
IUnitOfWorkManager unitOfWorkManager, |
|||
IConnectionStringResolver connectionStringResolver, |
|||
TMemoryDbContext dbContext) |
|||
{ |
|||
_unitOfWorkManager = unitOfWorkManager; |
|||
_connectionStringResolver = connectionStringResolver; |
|||
DbContext = dbContext; |
|||
} |
|||
|
|||
public IMemoryDatabase GetDatabase() |
|||
{ |
|||
var unitOfWork = _unitOfWorkManager.Current; |
|||
if (unitOfWork == null) |
|||
{ |
|||
throw new AbpException($"A {nameof(IMemoryDatabase)} instance can only be created inside a unit of work!"); |
|||
} |
|||
|
|||
var connectionString = _connectionStringResolver.Resolve<TMemoryDbContext>(); |
|||
var dbContextKey = $"{typeof(TMemoryDbContext).FullName}_{connectionString}"; |
|||
|
|||
var databaseApi = unitOfWork.GetOrAddDatabaseApi( |
|||
dbContextKey, |
|||
() => new MemoryDbDatabaseApi( |
|||
MemoryDatabaseManager.Get(connectionString) |
|||
)); |
|||
|
|||
return ((MemoryDbDatabaseApi)databaseApi).Database; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.MemoryDb.Tests</AssemblyName> |
|||
<PackageId>Volo.Abp.MemoryDb.Tests</PackageId> |
|||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.MemoryDb\Volo.Abp.MemoryDb.csproj" /> |
|||
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.TestApp\Volo.Abp.TestApp.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,31 @@ |
|||
using System; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.TestApp.MemoryDb; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.TestApp; |
|||
|
|||
namespace Volo.Abp.MemoryDb |
|||
{ |
|||
[DependsOn(typeof(TestAppModule), typeof(AbpMemoryDbModule), typeof(AbpAutofacModule))] |
|||
public class AbpMemoryDbTestModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
var connStr = Guid.NewGuid().ToString(); |
|||
|
|||
services.Configure<DbConnectionOptions>(options => |
|||
{ |
|||
options.ConnectionStrings.Default = connStr; |
|||
}); |
|||
|
|||
services.AddMemoryDbContext<TestAppMemoryDbContext>(options => |
|||
{ |
|||
options.WithDefaultRepositories(); |
|||
}); |
|||
|
|||
services.AddAssemblyOf<AbpMemoryDbModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.TestBase; |
|||
|
|||
namespace Volo.Abp.MemoryDb.Repositories |
|||
{ |
|||
public abstract class MemoryDbTestBase : AbpIntegratedTest<AbpMemoryDbTestModule> |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using System; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.TestApp.Domain; |
|||
using Xunit; |
|||
using System.Linq; |
|||
|
|||
namespace Volo.Abp.MemoryDb.Repositories |
|||
{ |
|||
public class MemoryDb_Basic_Repository_Tests : MemoryDbTestBase |
|||
{ |
|||
private readonly IQueryableRepository<Person> _personRepository; |
|||
|
|||
public MemoryDb_Basic_Repository_Tests() |
|||
{ |
|||
_personRepository = ServiceProvider.GetRequiredService<IQueryableRepository<Person>>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GetList() |
|||
{ |
|||
var people = _personRepository.GetList(); |
|||
people.Count.ShouldBeGreaterThan(0); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Insert() |
|||
{ |
|||
//Arrange
|
|||
var name = Guid.NewGuid().ToString(); |
|||
|
|||
//Act
|
|||
_personRepository.Insert(new Person(name, 42)); |
|||
|
|||
//Assert
|
|||
UseUnitOfWork(() => |
|||
{ |
|||
_personRepository.FirstOrDefault(p => p.Name == name).ShouldNotBeNull(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.MemoryDb; |
|||
using Volo.Abp.TestApp.Domain; |
|||
|
|||
namespace Volo.Abp.TestApp.MemoryDb |
|||
{ |
|||
public class TestAppMemoryDbContext : MemoryDbContext |
|||
{ |
|||
private static readonly Type[] EntityTypeList = new Type[] |
|||
{ |
|||
typeof(Person) |
|||
}; |
|||
|
|||
public override IReadOnlyList<Type> GetEntityTypes() |
|||
{ |
|||
return EntityTypeList; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.TestApp.Domain; |
|||
|
|||
namespace Volo.Abp.TestApp |
|||
{ |
|||
public class TestAppModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.AddAssemblyOf<TestAppModule>(); |
|||
} |
|||
|
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
using(IServiceScope scope = context.ServiceProvider.CreateScope()) |
|||
{ |
|||
var personRepository = scope.ServiceProvider.GetRequiredService<IRepository<Person>>(); |
|||
personRepository.Insert(new Person("Douglas", 42)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue