Skip to content

Commit e4dd189

Browse files
committed
Db migration implementation
1 parent 5e67e26 commit e4dd189

16 files changed

+647
-46
lines changed

Src/Services/Order/Order.API/Controllers/WeatherForecastController.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Order.Infrastructure.Data.Context;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
//using Microsoft.AspNetCore.Builder;
9+
10+
namespace Order.Infrastructure.Data.Extensions
11+
{
12+
public static class HostExtension
13+
{
14+
public static IHost MigrateDatabase<TContext>(this IHost host, Action<TContext, IServiceProvider> seeder, int? retry = 0)
15+
where TContext : DbContext
16+
{
17+
int retryAvailable = retry.Value;
18+
19+
using (var scope = host.Services.CreateScope())
20+
{
21+
var context = scope.ServiceProvider.GetService<TContext>();
22+
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TContext>>();
23+
24+
try
25+
{
26+
logger.LogInformation("Seeding Started...");
27+
InvokeSeeder(seeder, context, scope.ServiceProvider);
28+
logger.LogInformation("Seeding Ended...");
29+
}
30+
catch (Exception ex)
31+
{
32+
logger.LogError(ex.Message);
33+
if(retryAvailable < 50)
34+
{
35+
retryAvailable++;
36+
Thread.Sleep(2000);
37+
MigrateDatabase<TContext>(host, seeder, retryAvailable);
38+
}
39+
}
40+
}
41+
42+
return host;
43+
}
44+
45+
private static void InvokeSeeder<TContext>(Action<TContext, IServiceProvider> seeder, TContext? context, IServiceProvider serviceProvider)
46+
where TContext : DbContext
47+
{
48+
context.Database.Migrate();
49+
seeder(context, serviceProvider);
50+
}
51+
}
52+
}

Src/Services/Order/Order.API/Order.API.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.20">
11+
<PrivateAssets>all</PrivateAssets>
12+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13+
</PackageReference>
1014
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
1115
</ItemGroup>
1216

@@ -15,4 +19,8 @@
1519
<ProjectReference Include="..\Order.Infrastructure\Order.Infrastructure.csproj" />
1620
</ItemGroup>
1721

22+
<ItemGroup>
23+
<Folder Include="Controllers\" />
24+
</ItemGroup>
25+
1826
</Project>

Src/Services/Order/Order.API/Program.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
using Microsoft.EntityFrameworkCore;
12
using Order.Application;
3+
using Order.Infrastructure;
4+
using Order.Infrastructure.Data.Context;
5+
using Order.Infrastructure.Data.Extensions;
26

37
var builder = WebApplication.CreateBuilder(args);
48

9+
510
// Add services to the container.
611
builder.Services.AddApplicationServices();
12+
builder.Services.AddInfrastructureServices(builder.Configuration);
713

814
builder.Services.AddControllers();
915
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
@@ -12,6 +18,12 @@
1218

1319
var app = builder.Build();
1420

21+
app.MigrateDatabase<OrderDbContext>((context, services) =>
22+
{
23+
var logger = services.GetRequiredService<ILogger<OrderDbContext>>();
24+
OrderDbContextSeed.SeedAsync(context, logger).Wait();
25+
});
26+
1527
// Configure the HTTP request pipeline.
1628
if (app.Environment.IsDevelopment())
1729
{

Src/Services/Order/Order.API/WeatherForecast.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

Src/Services/Order/Order.API/appsettings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
{
2+
"ConnectionStrings": {
3+
"OrderDbConnString": "Data Source=(local)\\sqlexpress;Initial Catalog=OrderDB;Integrated Security=True;Encrypt=True;Trust Server Certificate=True"
4+
},
5+
"EmailSettings": {
6+
"ApiKey": "",
7+
"FromAddress": "",
8+
"FromName": ""
9+
},
210
"Logging": {
311
"LogLevel": {
412
"Default": "Information",
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Order.Domain.Common;
3+
using Order.Domain.Entities;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace Order.Infrastructure.Data.Context
11+
{
12+
public class OrderDbContext : DbContext
13+
{
14+
public OrderDbContext(DbContextOptions options) : base(options)
15+
{
16+
}
17+
18+
public DbSet<OrderEntity> Orders { get; set; }
19+
20+
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
21+
{
22+
var tracks = ChangeTracker.Entries<EntityBase>();
23+
foreach (var track in tracks)
24+
{
25+
switch (track.State)
26+
{
27+
//case EntityState.Detached:
28+
// break;
29+
//case EntityState.Unchanged:
30+
// break;
31+
//case EntityState.Deleted:
32+
// break;
33+
case EntityState.Modified:
34+
track.Entity.UpdatedBy = "testUser";
35+
track.Entity.UpdatedDate = DateTime.Now;
36+
break;
37+
case EntityState.Added:
38+
track.Entity.CreatedDate = DateTime.Now;
39+
track.Entity.CreatedBy = "testUser";
40+
break;
41+
default:
42+
break;
43+
}
44+
}
45+
46+
return base.SaveChangesAsync(cancellationToken);
47+
}
48+
}
49+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Microsoft.Extensions.Logging;
2+
using Order.Domain.Entities;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
namespace Order.Infrastructure.Data.Context
10+
{
11+
public static class OrderDbContextSeed
12+
{
13+
public static async Task SeedAsync(OrderDbContext dbContext, ILogger<OrderDbContext> logger)
14+
{
15+
if (dbContext == null)
16+
{
17+
throw new ArgumentNullException("Database Context is null.");
18+
}
19+
20+
if (!dbContext.Orders.Any())
21+
{
22+
dbContext.Orders.AddRange(GetDefaultOrders());
23+
await dbContext.SaveChangesAsync();
24+
}
25+
}
26+
27+
private static IEnumerable<OrderEntity> GetDefaultOrders()
28+
{
29+
var orders = new List<OrderEntity>
30+
{
31+
new() {UserName = "testUser", FirstName="Sovon", LastName="Biswas", EmailAddress="shbsovon@gmail.com", TotalPrice=130 }
32+
};
33+
34+
return orders;
35+
}
36+
}
37+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.Extensions.Configuration;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Order.Application.Contracts;
5+
using Order.Application.Models;
6+
using Order.Infrastructure.Data.Context;
7+
using Order.Infrastructure.Repositories;
8+
using Order.Infrastructure.Services;
9+
using System;
10+
using System.Collections.Generic;
11+
using System.Linq;
12+
using System.Text;
13+
using System.Threading.Tasks;
14+
15+
namespace Order.Infrastructure
16+
{
17+
public static class InfrastructureServiceRegistration
18+
{
19+
public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration)
20+
{
21+
services.AddDbContext<OrderDbContext>(op =>
22+
{
23+
op.UseSqlServer(configuration.GetConnectionString("OrderDbConnString"));
24+
});
25+
26+
services.AddScoped(typeof(IAsyncRepository<>), typeof(RepositoryBase<>));
27+
services.AddScoped<IOrderAsyncRepository, OrderRepository>();
28+
29+
services.Configure<EmailSettings>(c => configuration.GetSection("EmailSettings"));
30+
services.AddTransient<IEmailService, EmailService>();
31+
32+
return services;
33+
}
34+
}
35+
}

Src/Services/Order/Order.Infrastructure/Migrations/20240714191637_initMigration.Designer.cs

Lines changed: 110 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)