Skip to content

Commit

Permalink
fix(softdelete): Fix the problem that soft delete fails when using Is…
Browse files Browse the repository at this point in the history
…olationDbContext (#64)

* fix(Data.Contracts.EF): Fix the problem that soft delete fails when using IsolationDbContext

* test(EntityFramework): Add SoftDelete Integration Test

* chore: Remove invalid judgments
  • Loading branch information
zhenlei520 authored May 19, 2022
1 parent 4d42d34 commit 4c58790
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private static void UseSoftDelete(this MasaDbContextOptionsBuilder masaDbContext
var constructorInfo = softDeleteSaveChangesFilterType.GetConstructors().FirstOrDefault()!;
var invokeDelegate = InstanceBuilder.CreateInstanceDelegate(constructorInfo);

masaDbContextOptionsBuilder.Services.TryAdd(
masaDbContextOptionsBuilder.Services.Add(
new ServiceDescriptor(typeof(ISaveChangesFilter),
serviceProvider =>
{
Expand Down
16 changes: 16 additions & 0 deletions test/Masa.Contrib.Isolation.UoW.EF.Tests/CustomDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public CustomDbContext(MasaDbContextOptions options) : base(options) { }

public DbSet<User> User { get; set; }

public DbSet<Tag> Tag { get; set; }

protected override void OnModelCreatingExecuting(ModelBuilder builder)
{
builder.Entity<User>(ConfigureUserEntry);
Expand Down Expand Up @@ -40,3 +42,17 @@ public User()
this.Id = Guid.NewGuid();
}
}

public class Tag : ISoftDelete
{
public Guid Id { get; private set; }

public string Name { get; set; } = default!;

public bool IsDeleted { get; protected set; }

public Tag()
{
this.Id = Guid.NewGuid();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

<ItemGroup>
<ProjectReference Include="..\..\src\Configuration\Masa.Contrib.Configuration\Masa.Contrib.Configuration.csproj" />
<ProjectReference Include="..\..\src\Data\Masa.Contrib.Data.Contracts.EF\Masa.Contrib.Data.Contracts.EF.csproj" />
<ProjectReference Include="..\..\src\Data\Masa.Contrib.Data.EntityFrameworkCore.Sqlite\Masa.Contrib.Data.EntityFrameworkCore.Sqlite.csproj" />
<ProjectReference Include="..\..\src\Isolation\Masa.Contrib.Isolation.MultiEnvironment\Masa.Contrib.Isolation.MultiEnvironment.csproj" />
<ProjectReference Include="..\..\src\Isolation\Masa.Contrib.Isolation.MultiTenant\Masa.Contrib.Isolation.MultiTenant.csproj" />
Expand Down
95 changes: 80 additions & 15 deletions test/Masa.Contrib.Isolation.UoW.EF.Tests/TestIsolation.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

using Masa.BuildingBlocks.Data;

namespace Masa.Contrib.Isolation.UoW.EF.Tests;

[TestClass]
Expand Down Expand Up @@ -36,7 +34,8 @@ public void TestUseIsolationUoW2()
eventBuilder.Setup(builder => builder.Services).Returns(_services).Verifiable();
Assert.ThrowsException<ArgumentNullException>(() =>
{
eventBuilder.Object.UseIsolationUoW<CustomDbContext>(null!, dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));
eventBuilder.Object.UseIsolationUoW<CustomDbContext>(null!,
dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));
});
}

Expand Down Expand Up @@ -69,7 +68,8 @@ public void TestUseIsolationUoWByUseEnvironment()
{
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(builder => builder.Services).Returns(_services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiEnvironment(), dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiEnvironment(),
dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));

var serviceProvider = dispatcherOption.Object.Services.BuildServiceProvider();
Assert.IsNotNull(serviceProvider.GetService<IEnvironmentContext>());
Expand All @@ -81,7 +81,9 @@ public void TestUseIsolationUoWByUseMultiEnvironment()
{
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(builder => builder.Services).Returns(_services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiEnvironment().UseMultiEnvironment(), dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(
isolationBuilder => isolationBuilder.UseMultiEnvironment().UseMultiEnvironment(),
dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));

var serviceProvider = dispatcherOption.Object.Services.BuildServiceProvider();
Assert.IsTrue(serviceProvider.GetServices<IEnvironmentContext>().Count() == 1);
Expand All @@ -93,7 +95,8 @@ public void TestUseIsolationUoWByUseTenant()
{
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(builder => builder.Services).Returns(_services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiTenant(), dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiTenant(),
dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));

var serviceProvider = dispatcherOption.Object.Services.BuildServiceProvider();
Assert.IsNotNull(serviceProvider.GetService<ITenantContext>());
Expand All @@ -105,7 +108,8 @@ public void TestUseIsolationUoWByUseMultiTenant()
{
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(builder => builder.Services).Returns(_services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiTenant().UseMultiTenant(), dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiTenant().UseMultiTenant(),
dbOptionBuilder => dbOptionBuilder.UseTestSqlite(_connectionString));

var serviceProvider = dispatcherOption.Object.Services.BuildServiceProvider();
Assert.IsTrue(serviceProvider.GetServices<ITenantContext>().Count() == 1);
Expand All @@ -122,7 +126,8 @@ public void TestUseIsolation()
_services.AddSingleton<IConfiguration>(configurationRoot);
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(builder => builder.Services).Returns(_services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiTenant().UseMultiEnvironment(), dbOptionBuilder => dbOptionBuilder.UseSqlite());
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(
isolationBuilder => isolationBuilder.UseMultiTenant().UseMultiEnvironment(), dbOptionBuilder => dbOptionBuilder.UseSqlite());
var serviceProvider = _services.BuildServiceProvider();
var customDbContext = serviceProvider.GetRequiredService<CustomDbContext>();
var unitOfWorkAccessor = serviceProvider.GetRequiredService<IUnitOfWorkAccessor>();
Expand Down Expand Up @@ -164,7 +169,8 @@ public void TestUseIsolation()
unifOfWorkNew3.ServiceProvider.GetRequiredService<ITenantSetter>().SetTenant(new Tenant("00000000-0000-0000-0000-000000000002"));
unifOfWorkNew3.ServiceProvider.GetRequiredService<IEnvironmentSetter>().SetEnvironment("development");
var dbContext3 = unifOfWorkNew3.ServiceProvider.GetRequiredService<CustomDbContext>();
Assert.IsTrue(GetDataBaseConnectionString(dbContext3) == "data source=test2" && unitOfWorkAccessorNew3.CurrentDbContextOptions!.ConnectionString == "data source=test2");
Assert.IsTrue(GetDataBaseConnectionString(dbContext3) == "data source=test2" &&
unitOfWorkAccessorNew3.CurrentDbContextOptions!.ConnectionString == "data source=test2");

var unifOfWorkNew4 = unitOfWorkManager.CreateDbContext(true);
var unitOfWorkAccessorNew4 = unifOfWorkNew4.ServiceProvider.GetRequiredService<IUnitOfWorkAccessor>();
Expand Down Expand Up @@ -200,7 +206,8 @@ public void TestUseMultiEnvironment()
});
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(builder => builder.Services).Returns(_services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiEnvironment(), dbOptionBuilder => dbOptionBuilder.UseSqlite());
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder => isolationBuilder.UseMultiEnvironment(),
dbOptionBuilder => dbOptionBuilder.UseSqlite());
var serviceProvider = _services.BuildServiceProvider();
var customDbContext = serviceProvider.GetRequiredService<CustomDbContext>();
var unitOfWorkAccessor = serviceProvider.GetRequiredService<IUnitOfWorkAccessor>();
Expand All @@ -214,19 +221,22 @@ public void TestUseMultiEnvironment()
var unitOfWorkAccessorNew2 = unifOfWorkNew2.ServiceProvider.GetRequiredService<IUnitOfWorkAccessor>();
unifOfWorkNew2.ServiceProvider.GetRequiredService<IEnvironmentSetter>().SetEnvironment("dev");
var dbContext2 = unifOfWorkNew2.ServiceProvider.GetRequiredService<CustomDbContext>();
Assert.IsTrue(GetDataBaseConnectionString(dbContext2) == "data source=test5" && unitOfWorkAccessorNew2.CurrentDbContextOptions!.ConnectionString == "data source=test5");
Assert.IsTrue(GetDataBaseConnectionString(dbContext2) == "data source=test5" &&
unitOfWorkAccessorNew2.CurrentDbContextOptions!.ConnectionString == "data source=test5");

var unifOfWorkNew3 = unitOfWorkManager.CreateDbContext(true);
var unitOfWorkAccessorNew3 = unifOfWorkNew3.ServiceProvider.GetRequiredService<IUnitOfWorkAccessor>();
unifOfWorkNew3.ServiceProvider.GetRequiredService<IEnvironmentSetter>().SetEnvironment("pro");
var dbContext3 = unifOfWorkNew3.ServiceProvider.GetRequiredService<CustomDbContext>();
Assert.IsTrue(GetDataBaseConnectionString(dbContext3) == "data source=test6" && unitOfWorkAccessorNew3.CurrentDbContextOptions!.ConnectionString == "data source=test6");
Assert.IsTrue(GetDataBaseConnectionString(dbContext3) == "data source=test6" &&
unitOfWorkAccessorNew3.CurrentDbContextOptions!.ConnectionString == "data source=test6");

var unifOfWorkNew4 = unitOfWorkManager.CreateDbContext(true);
var unitOfWorkAccessorNew4 = unifOfWorkNew4.ServiceProvider.GetRequiredService<IUnitOfWorkAccessor>();
unifOfWorkNew4.ServiceProvider.GetRequiredService<IEnvironmentSetter>().SetEnvironment("staging");
var dbContext4 = unifOfWorkNew4.ServiceProvider.GetRequiredService<CustomDbContext>();
Assert.IsTrue(GetDataBaseConnectionString(dbContext4) == "data source=test4" && unitOfWorkAccessorNew4.CurrentDbContextOptions!.ConnectionString == "data source=test4");
Assert.IsTrue(GetDataBaseConnectionString(dbContext4) == "data source=test4" &&
unitOfWorkAccessorNew4.CurrentDbContextOptions!.ConnectionString == "data source=test4");
}

[TestMethod]
Expand Down Expand Up @@ -254,7 +264,8 @@ public void TestUseMultiTenant()
});
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(builder => builder.Services).Returns(_services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext, int>(isolationBuilder => isolationBuilder.UseMultiTenant(), dbOptionBuilder => dbOptionBuilder.UseSqlite());
dispatcherOption.Object.UseIsolationUoW<CustomDbContext, int>(isolationBuilder => isolationBuilder.UseMultiTenant(),
dbOptionBuilder => dbOptionBuilder.UseSqlite());
var serviceProvider = _services.BuildServiceProvider();
var customDbContext = serviceProvider.GetRequiredService<CustomDbContext>();
var unitOfWorkAccessor = serviceProvider.GetRequiredService<IUnitOfWorkAccessor>();
Expand Down Expand Up @@ -293,7 +304,8 @@ public void TestUseMultiTenantAndAddMasaConfiguration()
builder.AddMasaConfiguration();
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(opt => opt.Services).Returns(builder.Services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext, int>(isolationBuilder => isolationBuilder.UseMultiEnvironment(), dbOptionBuilder => dbOptionBuilder.UseSqlite());
dispatcherOption.Object.UseIsolationUoW<CustomDbContext, int>(isolationBuilder => isolationBuilder.UseMultiEnvironment(),
dbOptionBuilder => dbOptionBuilder.UseSqlite());
var serviceProvider = builder.Services.BuildServiceProvider();
var customDbContext = serviceProvider.GetRequiredService<CustomDbContext>();
var unitOfWorkAccessor = serviceProvider.GetRequiredService<IUnitOfWorkAccessor>();
Expand All @@ -302,5 +314,58 @@ public void TestUseMultiTenantAndAddMasaConfiguration()
Assert.IsTrue(currentDbContextOptions.ConnectionString == "data source=test1");
}

[TestMethod]
public async Task TestUseMultiTenantAndUseFilterAsync()
{
var services = new ServiceCollection();
services.Configure<IsolationDbConnectionOptions>(option =>
{
option.ConnectionStrings = new ConnectionStrings()
{
DefaultConnection = $"data source=test_{Guid.NewGuid()}"
};
option.IsolationConnectionStrings = new List<IsolationOptions>
{
new()
{
ConnectionString = $"data source=test_{Guid.NewGuid()}",
TenantId = "1"
}
};
});
Mock<IDispatcherOptions> dispatcherOption = new();
dispatcherOption.Setup(opt => opt.Services).Returns(services).Verifiable();
dispatcherOption.Object.UseIsolationUoW<CustomDbContext>(isolationBuilder =>
isolationBuilder.UseMultiTenant(),
dbOptionBuilder => dbOptionBuilder.UseSqlite().UseFilter().UseFilter());

var serviceProvider = services.BuildServiceProvider();
var customDbContext = serviceProvider.GetRequiredService<CustomDbContext>();
await customDbContext.Database.EnsureCreatedAsync();
var tag = new Tag()
{
Name = "Tom"
};
await customDbContext.Set<Tag>().AddAsync(tag);
await customDbContext.SaveChangesAsync();

Assert.IsTrue(await customDbContext.Set<Tag>().CountAsync() == 1);

tag = await customDbContext.Set<Tag>().FirstOrDefaultAsync(t => t.Id == tag.Id);
Assert.IsNotNull(tag);

customDbContext.Set<Tag>().Remove(tag);
await customDbContext.SaveChangesAsync();
Assert.IsTrue(await customDbContext.Set<Tag>().CountAsync() == 0);

var dataFilter = serviceProvider.GetRequiredService<IDataFilter>();
using (dataFilter.Disable<ISoftDelete>())
{
Assert.IsTrue(await customDbContext.Set<Tag>().CountAsync() == 1);
tag = await customDbContext.Set<Tag>().FirstOrDefaultAsync(t => t.Id == tag.Id);
Assert.IsNotNull(tag);
}
}

private string GetDataBaseConnectionString(CustomDbContext dbContext) => dbContext.Database.GetConnectionString()!;
}
3 changes: 3 additions & 0 deletions test/Masa.Contrib.Isolation.UoW.EF.Tests/_Imports.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

global using Masa.BuildingBlocks.Data;
global using Masa.BuildingBlocks.Data.Contracts.DataFiltering;
global using Masa.BuildingBlocks.Data.UoW;
global using Masa.BuildingBlocks.Dispatcher.Events;
global using Masa.BuildingBlocks.Isolation.Environment;
global using Masa.BuildingBlocks.Isolation.MultiTenant;
global using Masa.BuildingBlocks.Isolation.Options;
global using Masa.Contrib.Configuration;
global using Masa.Contrib.Data.Contracts.EF;
global using Masa.Contrib.Data.EntityFrameworkCore;
global using Masa.Contrib.Data.EntityFrameworkCore.Sqlite;
global using Masa.Contrib.Isolation.MultiEnvironment;
Expand Down

0 comments on commit 4c58790

Please sign in to comment.