Skip to content

Commit 9317dfe

Browse files
committed
phase 1: refactor efcore (cont.)
1 parent 445b200 commit 9317dfe

29 files changed

+341
-234
lines changed
0 Bytes
Binary file not shown.

.vs/netcorekit/v16/.suo

20.5 KB
Binary file not shown.

netcorekit.sln

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{92D6
2424
samples\readme.md = samples\readme.md
2525
EndProjectSection
2626
EndProject
27-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{1317E2B0-8834-4770-9759-9CD0D9E84D28}"
27+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1317E2B0-8834-4770-9759-9CD0D9E84D28}"
2828
EndProject
2929
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A1CCC105-67B3-45AE-9A74-DD6716521708}"
3030
ProjectSection(SolutionItems) = preProject
@@ -91,6 +91,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCoreKit.RestTemplate.Mon
9191
EndProject
9292
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCoreKit.RestTemplate.Standard", "templates\NetCoreKit.RestTemplate.Standard\NetCoreKit.RestTemplate.Standard.csproj", "{D175B413-2373-46C9-86EB-65329AFF2B98}"
9393
EndProject
94+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCoreKit.Infrastructure.EfCore.Tests", "src\NetCoreKit.Infrastructure.EfCore.Tests\NetCoreKit.Infrastructure.EfCore.Tests.csproj", "{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}"
95+
EndProject
9496
Global
9597
GlobalSection(SolutionConfigurationPlatforms) = preSolution
9698
Debug|Any CPU = Debug|Any CPU
@@ -315,6 +317,14 @@ Global
315317
{D175B413-2373-46C9-86EB-65329AFF2B98}.Release|Any CPU.Build.0 = Release|Any CPU
316318
{D175B413-2373-46C9-86EB-65329AFF2B98}.Release|x86.ActiveCfg = Release|Any CPU
317319
{D175B413-2373-46C9-86EB-65329AFF2B98}.Release|x86.Build.0 = Release|Any CPU
320+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
321+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
322+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Debug|x86.ActiveCfg = Debug|Any CPU
323+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Debug|x86.Build.0 = Debug|Any CPU
324+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
325+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Release|Any CPU.Build.0 = Release|Any CPU
326+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Release|x86.ActiveCfg = Release|Any CPU
327+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3}.Release|x86.Build.0 = Release|Any CPU
318328
EndGlobalSection
319329
GlobalSection(SolutionProperties) = preSolution
320330
HideSolutionNode = FALSE
@@ -350,6 +360,7 @@ Global
350360
{907308F6-D213-4FC8-B761-98976954B285} = {4A2D1031-E1FD-43BB-B8D3-F570F4020A29}
351361
{4BC63394-EFEF-499E-9D43-39AA96244502} = {4A2D1031-E1FD-43BB-B8D3-F570F4020A29}
352362
{D175B413-2373-46C9-86EB-65329AFF2B98} = {4A2D1031-E1FD-43BB-B8D3-F570F4020A29}
363+
{B4C4A9F0-00F0-45D8-8A82-60870EBD17A3} = {1317E2B0-8834-4770-9759-9CD0D9E84D28}
353364
EndGlobalSection
354365
GlobalSection(ExtensibilityGlobals) = postSolution
355366
SolutionGuid = {B9325AE8-21A8-4D46-9B04-38BD2BC35C0F}

samples/TodoApi/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void ConfigureServices(IServiceCollection services)
2424
);
2525

2626
services.AddDomainEventBus();
27-
services.AddRedisBus();
27+
//services.AddRedisBus(); //todo: enabled it if using a broker
2828
}
2929

3030
public void Configure(IApplicationBuilder app)

src/NetCoreKit.Domain/AggregateRoot.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@
66

77
namespace NetCoreKit.Domain
88
{
9-
public interface IAggregateRoot : IAggregateRootWithType<Guid>
9+
public interface IAggregateRoot : IAggregateRootWithId<Guid>
1010
{
1111
}
1212

13-
public interface IAggregateRootWithType<TId> : IEntityWithId<TId>
13+
public interface IAggregateRootWithId<TId> : IEntityWithId<TId>
1414
{
15-
IAggregateRootWithType<TId> ApplyEvent(IEvent payload);
15+
IAggregateRootWithId<TId> ApplyEvent(IEvent payload);
1616
List<IEvent> GetUncommittedEvents();
1717
void ClearUncommittedEvents();
18-
IAggregateRootWithType<TId> RemoveEvent(IEvent @event);
19-
IAggregateRootWithType<TId> AddEvent(IEvent uncommittedEvent);
20-
IAggregateRootWithType<TId> RegisterHandler<T>(Action<T> handler);
18+
IAggregateRootWithId<TId> RemoveEvent(IEvent @event);
19+
IAggregateRootWithId<TId> AddEvent(IEvent uncommittedEvent);
20+
IAggregateRootWithId<TId> RegisterHandler<T>(Action<T> handler);
2121
}
2222

2323
public abstract class AggregateRootBase : AggregateRootWithIdBase<Guid>, IAggregateRoot
@@ -27,7 +27,7 @@ protected AggregateRootBase() : base(GenerateId())
2727
}
2828
}
2929

30-
public abstract class AggregateRootWithIdBase<TId> : EntityWithIdBase<TId>, IAggregateRootWithType<TId>
30+
public abstract class AggregateRootWithIdBase<TId> : EntityWithIdBase<TId>, IAggregateRootWithId<TId>
3131
{
3232
private readonly IDictionary<Type, Action<object>> _handlers = new ConcurrentDictionary<Type, Action<object>>();
3333
private readonly List<IEvent> _uncommittedEvents = new List<IEvent>();
@@ -39,14 +39,14 @@ protected AggregateRootWithIdBase(TId id) : base(id)
3939

4040
public int Version { get; protected set; }
4141

42-
public IAggregateRootWithType<TId> AddEvent(IEvent uncommittedEvent)
42+
public IAggregateRootWithId<TId> AddEvent(IEvent uncommittedEvent)
4343
{
4444
_uncommittedEvents.Add(uncommittedEvent);
4545
ApplyEvent(uncommittedEvent);
4646
return this;
4747
}
4848

49-
public IAggregateRootWithType<TId> ApplyEvent(IEvent payload)
49+
public IAggregateRootWithId<TId> ApplyEvent(IEvent payload)
5050
{
5151
if (!_handlers.ContainsKey(payload.GetType()))
5252
return this;
@@ -65,13 +65,13 @@ public List<IEvent> GetUncommittedEvents()
6565
return _uncommittedEvents;
6666
}
6767

68-
public IAggregateRootWithType<TId> RegisterHandler<T>(Action<T> handler)
68+
public IAggregateRootWithId<TId> RegisterHandler<T>(Action<T> handler)
6969
{
7070
_handlers.Add(typeof(T), e => handler((T)e));
7171
return this;
7272
}
7373

74-
public IAggregateRootWithType<TId> RemoveEvent(IEvent @event)
74+
public IAggregateRootWithId<TId> RemoveEvent(IEvent @event)
7575
{
7676
if (_uncommittedEvents.Find(e => e == @event) != null)
7777
_uncommittedEvents.Remove(@event);

src/NetCoreKit.Domain/QueryRepository.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,15 @@ namespace NetCoreKit.Domain
55
{
66
public interface IQueryRepositoryFactory
77
{
8-
IQueryRepositoryWithType<TEntity, TId> QueryRepository<TEntity, TId>() where TEntity : IAggregateRootWithType<TId>;
9-
IQueryRepository<TEntity> QueryRepository<TEntity>() where TEntity : IAggregateRoot;
8+
IQueryRepositoryWithId<TEntity, TId> QueryRepository<TEntity, TId>() where TEntity : class, IAggregateRootWithId<TId>;
9+
IQueryRepository<TEntity> QueryRepository<TEntity>() where TEntity : class, IAggregateRoot;
1010
}
1111

12-
public interface IQueryRepository<TEntity> : IQueryRepositoryWithType<TEntity, Guid>
13-
where TEntity : IAggregateRootWithType<Guid>
12+
public interface IQueryRepository<TEntity> : IQueryRepositoryWithId<TEntity, Guid> where TEntity : IAggregateRoot
1413
{
1514
}
1615

17-
public interface IQueryRepositoryWithType<TEntity, TId>
18-
where TEntity : IAggregateRootWithType<TId>
16+
public interface IQueryRepositoryWithId<TEntity, TId> where TEntity : IAggregateRootWithId<TId>
1917
{
2018
IQueryable<TEntity> Queryable();
2119
}

src/NetCoreKit.Domain/UnitOfWork.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ public interface IUnitOfWorkAsync : IRepositoryFactoryAsync, IDisposable
1212

1313
public interface IRepositoryFactoryAsync
1414
{
15-
IRepositoryWithTypeAsync<TEntity, TId> RepositoryAsync<TEntity, TId>() where TEntity : class, IAggregateRootWithType<TId>;
15+
IRepositoryWithIdAsync<TEntity, TId> RepositoryAsync<TEntity, TId>() where TEntity : class, IAggregateRootWithId<TId>;
1616
IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : class, IAggregateRoot;
1717
}
1818

19-
public interface IRepositoryAsync<TEntity> : IRepositoryWithTypeAsync<TEntity, Guid> where TEntity : IAggregateRoot
19+
public interface IRepositoryAsync<TEntity> : IRepositoryWithIdAsync<TEntity, Guid> where TEntity : IAggregateRoot
2020
{
2121
}
2222

23-
public interface IRepositoryWithTypeAsync<TEntity, TId> where TEntity : IAggregateRootWithType<TId>
23+
public interface IRepositoryWithIdAsync<TEntity, TId> where TEntity : IAggregateRootWithId<TId>
2424
{
2525
Task<TEntity> AddAsync(TEntity entity);
2626
Task<TEntity> UpdateAsync(TEntity entity);

src/NetCoreKit.Infrastructure.AspNetCore.All/NetCoreKit.Infrastructure.AspNetCore.All.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
<PackageReference Include="AutoMapper" Version="8.0.0" />
2323
<PackageReference Include="MessagePack.AspNetCoreMvcFormatter" Version="1.7.3.4" />
2424
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
25-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="3.1.1" />
26-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="3.1.0" />
25+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="3.1.2" />
26+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="3.2.0" />
2727
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
2828
<PackageReference Include="Microsoft.Extensions.Http" Version="2.2.0" />
2929
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.2.0" />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.2</TargetFramework>
5+
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.0-preview-20181205-02" />
11+
<PackageReference Include="xunit" Version="2.4.0" />
12+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\NetCoreKit.Domain\NetCoreKit.Domain.csproj" />
17+
<ProjectReference Include="..\NetCoreKit.Infrastructure.EfCore\NetCoreKit.Infrastructure.EfCore.csproj" />
18+
<ProjectReference Include="..\NetCoreKit.Infrastructure\NetCoreKit.Infrastructure.csproj" />
19+
</ItemGroup>
20+
21+
<ItemGroup>
22+
<None Update="appsettings.json">
23+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
24+
</None>
25+
</ItemGroup>
26+
27+
</Project>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System.Linq;
2+
using System.Threading.Tasks;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using NetCoreKit.Domain;
7+
using NetCoreKit.Infrastructure.EfCore.Db;
8+
using NetCoreKit.Infrastructure.EfCore.Extensions;
9+
using Xunit;
10+
11+
namespace NetCoreKit.Infrastructure.EfCore.Tests
12+
{
13+
public class TestEntity : AggregateRootBase
14+
{
15+
}
16+
17+
public class TestDbContext : AppDbContext
18+
{
19+
public TestDbContext(DbContextOptions<TestDbContext> options, IConfiguration config, IDomainEventDispatcher eventBus = null)
20+
: base(options, config, eventBus)
21+
{
22+
}
23+
}
24+
25+
public class RepositoryTest
26+
{
27+
private readonly IServiceCollection _services;
28+
29+
public RepositoryTest()
30+
{
31+
// arrange
32+
_services = new ServiceCollection();
33+
var config = ConfigurationHelper.GetConfiguration();
34+
_services.AddScoped<IConfiguration>(x => config);
35+
_services.AddDbContext<TestDbContext>((sp, o) =>
36+
{
37+
o.UseInMemoryDatabase("default_db");
38+
});
39+
40+
_services.AddScoped<DbContext>(resolver => resolver.GetService<TestDbContext>());
41+
_services.AddGenericRepository();
42+
}
43+
44+
[Fact]
45+
public async Task CanCommandOnGenericRepo()
46+
{
47+
// command
48+
var uow = _services.BuildServiceProvider().GetService<IUnitOfWorkAsync>();
49+
var testCommandRepo = uow.RepositoryAsync<TestEntity>();
50+
await testCommandRepo.AddAsync(new TestEntity());
51+
await testCommandRepo.AddAsync(new TestEntity());
52+
var result = await uow.SaveChangesAsync(default);
53+
54+
// assert
55+
Assert.True(result >= 0);
56+
}
57+
58+
[Fact]
59+
public async Task CanQueryOnGenericRepo()
60+
{
61+
// query
62+
var repoFactory = _services.BuildServiceProvider().GetService<IQueryRepositoryFactory>();
63+
var testQueryRepo = repoFactory.QueryRepository<TestEntity>();
64+
var result = await testQueryRepo.ListAsync<TestDbContext, TestEntity>();
65+
66+
// assert
67+
Assert.NotNull(result.ToList());
68+
}
69+
}
70+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"QualifiedAssemblyPattern": "NetCoreKit.*",
3+
"EfCore": {
4+
"Cache": {
5+
"ExpiredTime": 60 // seconds
6+
}
7+
}
8+
}

src/NetCoreKit.Infrastructure.EfCore/Db/AppDbContext.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ protected AppDbContext(DbContextOptions options, IConfiguration config, IDomainE
2626
protected override void OnModelCreating(ModelBuilder builder)
2727
{
2828
var typeToRegisters = new List<Type>();
29-
3029
var ourModules = _config.LoadFullAssemblies();
3130

3231
typeToRegisters.AddRange(ourModules.SelectMany(m => m.DefinedTypes));
@@ -55,31 +54,37 @@ public override int SaveChanges()
5554
}
5655

5756
/// <summary>
58-
/// Source:
59-
/// https://github.com/ardalis/CleanArchitecture/blob/master/src/CleanArchitecture.Infrastructure/Data/AppDbContext.cs
57+
/// Source:
58+
/// https://github.com/ardalis/CleanArchitecture/blob/master/src/CleanArchitecture.Infrastructure/Data/AppDbContext.cs
6059
/// </summary>
6160
private void SaveChangesWithEvents(IDomainEventDispatcher domainEventDispatcher)
6261
{
63-
var entitiesWithEvents = ChangeTracker.Entries<IAggregateRoot>()
62+
var entitiesWithEvents = ChangeTracker
63+
.Entries()
6464
.Select(e => e.Entity)
65-
.Where(e => e.GetUncommittedEvents().Any())
65+
.Where(e =>
66+
!e.GetType().BaseType.IsGenericType &&
67+
typeof(AggregateRootBase).IsAssignableFrom(e.GetType()))
68+
.Where(e => ((IAggregateRoot)e).GetUncommittedEvents().Any())
6669
.ToArray();
6770

6871
foreach (var entity in entitiesWithEvents)
6972
{
70-
var events = entity.GetUncommittedEvents().ToArray();
71-
entity.GetUncommittedEvents().Clear();
73+
var events = ((IAggregateRoot)entity).GetUncommittedEvents().ToArray();
74+
((IAggregateRoot)entity).GetUncommittedEvents().Clear();
7275
foreach (var domainEvent in events)
7376
domainEventDispatcher.Dispatch(domainEvent);
7477
}
7578
}
7679

7780
private static void RegisterEntities(ModelBuilder modelBuilder, IEnumerable<Type> typeToRegisters)
7881
{
79-
// TODO: will optimize this more
80-
var types = typeToRegisters.Where(x =>
81-
typeof(IEntity).IsAssignableFrom(x) &&
82-
!x.GetTypeInfo().IsAbstract);
82+
var concreteTypes = typeToRegisters.Where(x => !x.GetTypeInfo().IsAbstract && !x.GetTypeInfo().IsInterface);
83+
var types = concreteTypes
84+
.Where(x =>
85+
typeof(EntityBase).IsAssignableFrom(x) ||
86+
typeof(AggregateRootBase).IsAssignableFrom(x)
87+
);
8388

8489
foreach (var type in types) modelBuilder.Entity(type);
8590
}

0 commit comments

Comments
 (0)