Skip to content

Commit d6a0883

Browse files
committed
Atualização de versões e melhorias em testes e configurações
* Atualização de versões - Alterado `PersistVer` para `0.8.2` e `WorkContextVer` para `0.8.1`. * Referências de projeto - Adicionadas referências para PostgreSql, Sqlite e SqlServer nos testes. * Melhoria de testes - Novo método de teste para o contexto SQLite em memória. - Criada classe `PersonMapping` para configuração da entidade `Person`. * Comentários e documentação - Atualizados comentários em interfaces para inglês. - Melhorados comentários em métodos de extensão. * Extensões de contexto SQLite - Novos métodos para garantir criação e semeadura do banco de dados. - Adicionada delegate para configurar conexões SQLite em memória. * Dependências de projeto - Removida referência ao `Microsoft.EntityFrameworkCore.Sqlite` e adicionada ao `RoyalCode.WorkContext.Sqlite`. * Mapeamento de entidades - Melhorados mapeamentos para `Blog`, `Post`, `Thread`, `Comment` e `Author`.
1 parent 690a78b commit d6a0883

File tree

13 files changed

+280
-25
lines changed

13 files changed

+280
-25
lines changed

RoyalCode.EnterprisePatterns/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<DomainVer>0.8.0</DomainVer>
1010
<DomainPreview></DomainPreview>
1111

12-
<PersistVer>0.8.1</PersistVer>
12+
<PersistVer>0.8.2</PersistVer>
1313
<PersistPreview></PersistPreview>
1414

1515
<CommandVer>0.1.0</CommandVer>

RoyalCode.EnterprisePatterns/RoyalCode.Persistence.Tests/RoyalCode.Persistence.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
<ProjectReference Include="..\RoyalCode.UnitOfWork.EntityFramework\RoyalCode.UnitOfWork.EntityFramework.csproj" />
1212
<ProjectReference Include="..\RoyalCode.WorkContext.EntityFramework\RoyalCode.WorkContext.EntityFramework.csproj" />
1313
<ProjectReference Include="..\RoyalCode.WorkContext.Abstractions\RoyalCode.WorkContext.Abstractions.csproj" />
14+
<ProjectReference Include="..\RoyalCode.WorkContext.PostgreSql\RoyalCode.WorkContext.PostgreSql.csproj" />
15+
<ProjectReference Include="..\RoyalCode.WorkContext.Sqlite\RoyalCode.WorkContext.Sqlite.csproj" />
16+
<ProjectReference Include="..\RoyalCode.WorkContext.SqlServer\RoyalCode.WorkContext.SqlServer.csproj" />
1417
</ItemGroup>
1518

1619
</Project>

RoyalCode.EnterprisePatterns/RoyalCode.Persistence.Tests/WorkContext/WorkContextBuilderTests.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Data.Sqlite;
22
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
34
using Microsoft.Extensions.DependencyInjection;
45
using RoyalCode.Persistence.Tests.Entities;
56
using RoyalCode.Repositories;
@@ -73,6 +74,50 @@ public void ConfigureWorkContextAndRepositoryAndSearch()
7374

7475
scope.Dispose();
7576
}
77+
78+
[Fact]
79+
public async Task Sqlite_AddSqliteInMemoryWorkContextDefault()
80+
{
81+
ServiceCollection services = new();
82+
83+
services.AddSqliteInMemoryWorkContextDefault()
84+
.EnsureDatabaseCreated()
85+
.ConfigureModel(b =>
86+
{
87+
b.ApplyConfigurationsFromAssembly(typeof(PersonMapping).Assembly);
88+
})
89+
.ConfigureRepositories(c =>
90+
{
91+
c.Add<Person>();
92+
})
93+
.ConfigureSearches(c =>
94+
{
95+
c.Add<Person>();
96+
});
97+
98+
var root = services.BuildServiceProvider();
99+
var scope = root.CreateScope();
100+
var sp = scope.ServiceProvider;
101+
102+
var workContext = sp.GetService<IWorkContext>();
103+
Assert.NotNull(workContext);
104+
105+
var defaultRepo = workContext.Repository<Person>();
106+
Assert.NotNull(defaultRepo);
107+
108+
var person = new Person { Name = "John Doe" };
109+
await defaultRepo.AddAsync(person);
110+
await workContext.SaveAsync();
111+
112+
var contextCriteria = workContext.Criteria<Person>();
113+
Assert.NotNull(contextCriteria);
114+
115+
var contextAllPersons = contextCriteria.Collect();
116+
Assert.NotNull(contextAllPersons);
117+
Assert.NotEmpty(contextAllPersons);
118+
119+
scope.Dispose();
120+
}
76121
}
77122

78123

@@ -93,4 +138,14 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
93138
}
94139
}
95140

141+
class PersonMapping : IEntityTypeConfiguration<Person>
142+
{
143+
public void Configure(EntityTypeBuilder<Person> builder)
144+
{
145+
builder.ToTable("Persons");
146+
builder.HasKey(p => p.Id);
147+
builder.Property(p => p.Name).IsRequired().HasMaxLength(100);
148+
}
149+
}
150+
96151
#endregion

RoyalCode.EnterprisePatterns/RoyalCode.UnitOfWork.EntityFramework/Configurations/IConfigureConventions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ public interface IConfigureConventions<TDbContext>
1010
where TDbContext : DbContext
1111
{
1212
/// <summary>
13-
/// Configure as convensões do <see cref="DbContext"/> através do <see cref="ModelConfigurationBuilder"/>.
13+
/// Configures conventions for the specified <see cref="ModelConfigurationBuilder"/>
14+
/// using the provided <typeparamref name="TDbContext"/>.
1415
/// </summary>
15-
/// <param name="builder">O <see cref="ModelConfigurationBuilder"/> a ser configurado.</param>
16+
/// <param name="builder">The builder used to configure conventions for the <typeparamref name="TDbContext"/>.</param>
1617
void Configure(ModelConfigurationBuilder builder);
1718
}

RoyalCode.EnterprisePatterns/RoyalCode.UnitOfWork.EntityFramework/Configurations/IConfigureModel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ public interface IConfigureModel<TDbContext>
99
where TDbContext : DbContext
1010
{
1111
/// <summary>
12-
/// Configura o <see cref="ModelBuilder"/> de um <see cref="DbContext"/>.
12+
/// Configures the <see cref="ModelBuilder"/> for the specified <see cref="DbContext"/>.
1313
/// </summary>
14-
/// <param name="modelBuilder"></param>
14+
/// <param name="modelBuilder">The <see cref="ModelBuilder"/> to configure.</param>
1515
public void Configure(ModelBuilder modelBuilder);
1616
}

RoyalCode.EnterprisePatterns/RoyalCode.UnitOfWork.EntityFramework/Configurations/IConfigureOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ public interface IConfigureOptions<TDbContext>
1010
where TDbContext : DbContext
1111
{
1212
/// <summary>
13-
/// Configure as opções do <see cref="DbContext"/> através do <see cref="DbContextOptionsBuilder"/>.
13+
/// Configures the options for the <see cref="DbContext"/> using the provided <see cref="DbContextOptionsBuilder"/>.
1414
/// </summary>
15-
/// <param name="optionsBuilder">O <see cref="DbContextOptionsBuilder"/> a ser configurado.</param>
15+
/// <param name="optionsBuilder">The <see cref="DbContextOptionsBuilder"/> to configure.</param>
1616
void Configure(DbContextOptionsBuilder optionsBuilder);
1717
}
Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
using Microsoft.EntityFrameworkCore.Infrastructure;
2+
using Microsoft.Extensions.DependencyInjection;
23
using RoyalCode.UnitOfWork.EntityFramework.Configurations;
34

45
namespace Microsoft.EntityFrameworkCore;
56

67
/// <summary>
7-
/// Métodos de extensão para <see cref="DbContext"/>.
8+
/// Extension methods for <see cref="DbContext"/>.
89
/// </summary>
910
public static class DbContextExtensions
1011
{
1112
/// <summary>
12-
/// Configura um <see cref="ModelBuilder"/> usando serviços de <see cref="IConfigureModel{TDbContext}"/>
13-
/// obtidos do <see cref="DbContext"/>.
13+
/// Configures a <see cref="ModelBuilder"/> using <see cref="IConfigureModel{TDbContext}"/> services
14+
/// obtained from the <see cref="DbContext"/>.
1415
/// </summary>
15-
/// <typeparam name="TDbContext">O tipo do DbContext.</typeparam>
16-
/// <param name="context">O DbContext.</param>
17-
/// <param name="modelBuilder">O ModelBuilder do DbContext.</param>
16+
/// <typeparam name="TDbContext">The type of DbContext.</typeparam>
17+
/// <param name="context">The DbContext.</param>
18+
/// <param name="modelBuilder">The ModelBuilder of the DbContext.</param>
1819
public static void ConfigureModelWithServices<TDbContext>(
1920
this TDbContext context, ModelBuilder modelBuilder)
2021
where TDbContext : DbContext
2122
{
22-
var configurations = context.GetService<IEnumerable<IConfigureModel<TDbContext>>>();
23+
var configurations = context.GetApplicationService<IEnumerable<IConfigureModel<TDbContext>>>();
2324
if (configurations is null)
2425
return;
2526

@@ -28,21 +29,45 @@ public static void ConfigureModelWithServices<TDbContext>(
2829
}
2930

3031
/// <summary>
31-
/// Configura um <see cref="ModelConfigurationBuilder"/> usando serviços
32-
/// de <see cref="IConfigureConventions{TDbContext}"/> obtidos do <see cref="DbContext"/>.
32+
/// Configures a <see cref="ModelConfigurationBuilder"/> using
33+
/// <see cref="IConfigureConventions{TDbContext}"/> services obtained from the <see cref="DbContext"/>.
3334
/// </summary>
34-
/// <typeparam name="TDbContext">O tipo do DbContext.</typeparam>
35-
/// <param name="context">O DbContext.</param>
36-
/// <param name="configurationBuilder">As configurações do DbContext.</param>
35+
/// <typeparam name="TDbContext">The type of DbContext.</typeparam>
36+
/// <param name="context">The DbContext.</param>
37+
/// <param name="configurationBuilder">The configuration builder of the DbContext.</param>
3738
public static void ConfigureConventionsWithServices<TDbContext>(
3839
this TDbContext context, ModelConfigurationBuilder configurationBuilder)
3940
where TDbContext : DbContext
4041
{
41-
var configurations = context.GetService<IEnumerable<IConfigureConventions<TDbContext>>>();
42+
var configurations = context.GetApplicationService<IEnumerable<IConfigureConventions<TDbContext>>>();
4243
if (configurations is null)
4344
return;
4445

4546
foreach (var configuration in configurations)
4647
configuration.Configure(configurationBuilder);
4748
}
49+
50+
/// <summary>
51+
/// Gets a service registered in the application's service provider associated with the <see cref="DbContext"/>.
52+
/// </summary>
53+
/// <typeparam name="TService">The type of service to obtain.</typeparam>
54+
/// <param name="accessor">Access to the service provider of the DbContext.</param>
55+
/// <returns>The requested service instance.</returns>
56+
/// <exception cref="InvalidOperationException">
57+
/// If there is no service of type <typeparamref name="TService"/> registered
58+
/// in the application's service provider associated with the <see cref="DbContext"/>,
59+
/// or when the application's service provider is not configured for the <see cref="DbContext"/>.
60+
/// </exception>
61+
public static TService GetApplicationService<TService>(this IInfrastructure<IServiceProvider> accessor)
62+
where TService : class
63+
{
64+
var sp = accessor.Instance;
65+
66+
return (sp.GetService<IDbContextOptions>()
67+
?.Extensions.OfType<CoreOptionsExtension>().FirstOrDefault()
68+
?.ApplicationServiceProvider
69+
?.GetRequiredService<TService>())
70+
?? throw new InvalidOperationException(
71+
$"No service of type '{typeof(TService).FullName}' is registered in the DbContext.");
72+
}
4873
}

RoyalCode.EnterprisePatterns/RoyalCode.WorkContext.Sqlite/Extensions/SqliteWorkContextExtensions.cs

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static IWorkContextBuilder<TDbContext> AddSqliteWorkContext<TDbContext>(
7171
/// </returns>
7272
public static IWorkContextBuilder<DefaultDbContext> AddSqliteInMemoryWorkContextDefault(
7373
this IServiceCollection services,
74-
Action<SqliteConnection, IServiceProvider>? configureConnection = null,
74+
ConfigureInMemorySqliteConnection<DefaultDbContext>? configureConnection = null,
7575
ServiceLifetime lifetime = ServiceLifetime.Scoped)
7676
{
7777
return services.AddSqliteInMemoryWorkContext<DefaultDbContext>(configureConnection, lifetime);
@@ -90,7 +90,7 @@ public static IWorkContextBuilder<DefaultDbContext> AddSqliteInMemoryWorkContext
9090
/// </returns>
9191
public static IWorkContextBuilder<TDbContext> AddSqliteInMemoryWorkContext<TDbContext>(
9292
this IServiceCollection services,
93-
Action<SqliteConnection, IServiceProvider>? configureConnection = null,
93+
ConfigureInMemorySqliteConnection<TDbContext>? configureConnection = null,
9494
ServiceLifetime lifetime = ServiceLifetime.Scoped)
9595
where TDbContext : DbContext
9696
{
@@ -109,6 +109,9 @@ public static IWorkContextBuilder<TDbContext> AddSqliteInMemoryWorkContext<TDbCo
109109
conn.Open();
110110
if (configureConnection is not null)
111111
configureConnection(connection, provider);
112+
113+
provider.GetService<InternalInMemorySqliteConfigureConnection<TDbContext>>()
114+
?.Configure(conn, provider);
112115
}
113116

114117
options.UseSqlite(conn);
@@ -132,4 +135,113 @@ public static IWorkContextBuilder<TDbContext> ConfigureSqliteOptions<TDbContext>
132135
configure(new SqliteDbContextOptionsBuilder(ob));
133136
});
134137
}
138+
139+
/// <summary>
140+
/// Adds a configuration to ensure the database is created when the work context is built.
141+
/// </summary>
142+
/// <typeparam name="TDbContext">The type of the DbContext used in the work context.</typeparam>
143+
/// <param name="builder">The work context builder to which the configuration will be added.</param>
144+
/// <returns>The same builder for chained calls.</returns>
145+
public static IWorkContextBuilder<TDbContext> EnsureDatabaseCreated<TDbContext>(
146+
this IWorkContextBuilder<TDbContext> builder)
147+
where TDbContext : DbContext
148+
{
149+
InternalInMemorySqliteConfigureConnection<TDbContext>.GetFromServices(builder.Services)
150+
.Configure((connection, sp) =>
151+
{
152+
using var scope = sp.CreateScope();
153+
var context = scope.ServiceProvider.GetRequiredService<TDbContext>();
154+
context.Database.EnsureCreated();
155+
});
156+
157+
return builder;
158+
}
159+
160+
/// <summary>
161+
/// Adds a configuration to seed the database with initial data when the work context is built.
162+
/// </summary>
163+
/// <typeparam name="TDbContext">The type of the DbContext used in the work context.</typeparam>
164+
/// <param name="builder">The work context builder to which the configuration will be added.</param>
165+
/// <param name="seedAction">The action to seed the database, which receives the <see cref="DbContext"/>.</param>
166+
/// <returns>The same builder for chained calls.</returns>
167+
public static IWorkContextBuilder<TDbContext> SeedDatabase<TDbContext>(
168+
this IWorkContextBuilder<TDbContext> builder,
169+
Func<TDbContext, Task> seedAction)
170+
where TDbContext : DbContext
171+
{
172+
InternalInMemorySqliteConfigureConnection<TDbContext>.GetFromServices(builder.Services)
173+
.Configure(async (connection, sp) =>
174+
{
175+
using var scope = sp.CreateScope();
176+
var context = scope.ServiceProvider.GetRequiredService<TDbContext>();
177+
await seedAction(context);
178+
});
179+
180+
return builder;
181+
}
182+
183+
/// <summary>
184+
/// Adds a configuration to seed the database with initial data when the work context is built,
185+
/// </summary>
186+
/// <typeparam name="TDbContext">The type of the DbContext used in the work context.</typeparam>
187+
/// <param name="builder">The work context builder to which the configuration will be added.</param>
188+
/// <param name="seedAction">The action to seed the database, which receives the <see cref="DbContext"/> and <see cref="IServiceProvider"/>.</param>
189+
/// <returns>The same builder for chained calls.</returns>
190+
public static IWorkContextBuilder<TDbContext> SeedDatabase<TDbContext>(
191+
this IWorkContextBuilder<TDbContext> builder,
192+
Func<TDbContext, IServiceProvider, Task> seedAction)
193+
where TDbContext : DbContext
194+
{
195+
InternalInMemorySqliteConfigureConnection<TDbContext>.GetFromServices(builder.Services)
196+
.Configure(async (connection, sp) =>
197+
{
198+
using var scope = sp.CreateScope();
199+
var context = scope.ServiceProvider.GetRequiredService<TDbContext>();
200+
await seedAction(context, scope.ServiceProvider);
201+
});
202+
203+
return builder;
204+
}
135205
}
206+
207+
/// <summary>
208+
/// A delegate to configure an in-memory SQLite connection for a specific <see cref="DbContext"/>.
209+
/// </summary>
210+
/// <typeparam name="TDb">The type of the DbContext.</typeparam>
211+
/// <param name="connection">The SQLite connection to configure.</param>
212+
/// <param name="sp">The IServiceProvider to use for service resolution.</param>
213+
public delegate void ConfigureInMemorySqliteConnection<TDb>(SqliteConnection connection, IServiceProvider sp)
214+
where TDb : DbContext;
215+
216+
internal sealed class InternalInMemorySqliteConfigureConnection<TDb>
217+
where TDb : DbContext
218+
{
219+
public static InternalInMemorySqliteConfigureConnection<TDb> GetFromServices(IServiceCollection services)
220+
{
221+
var descriptor = services.FirstOrDefault(d => d.ImplementationType == typeof(InternalInMemorySqliteConfigureConnection<TDb>));
222+
if (descriptor is null || descriptor.ImplementationInstance is not InternalInMemorySqliteConfigureConnection<TDb> options)
223+
{
224+
options = new InternalInMemorySqliteConfigureConnection<TDb>();
225+
services.AddSingleton(options);
226+
}
227+
return options;
228+
}
229+
230+
private ConfigureInMemorySqliteConnection<TDb>? configure;
231+
232+
public void Configure(SqliteConnection connection, IServiceProvider sp)
233+
{
234+
if (configure is null)
235+
return;
236+
237+
configure(connection, sp);
238+
}
239+
240+
public void Configure(ConfigureInMemorySqliteConnection<TDb> configure)
241+
{
242+
if (this.configure is null)
243+
this.configure = configure;
244+
else
245+
this.configure += configure;
246+
}
247+
}

RoyalCode.Examples/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22
<PropertyGroup>
33
<AspNetVer>9.0.0</AspNetVer>
4-
<WorkContextVer>0.8.0</WorkContextVer>
4+
<WorkContextVer>0.8.1</WorkContextVer>
55
<ProblemsVer>1.0.0-preview-4.4</ProblemsVer>
66
<GenVer>0.0.2</GenVer>
77
<SqliteVer>9.0.7</SqliteVer>

RoyalCode.Examples/RoyalCode.Examples.Api/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
builder.Services.AddOpenApi();
1010
builder.Services.AddBlobs();
1111

12-
builder.Services.AddWorkContext<AppDbContext>()
12+
builder.Services.AddSqliteInMemoryWorkContextDefault()
1313
.ConfigureDbContextWithService()
1414
.ConfigureBlogs()
1515
.AddUnitOfWorkAdapter();

0 commit comments

Comments
 (0)