Skip to content

Commit 506d5fd

Browse files
committed
(#125) Bulk Insert/Update/Delete/Merge
1 parent f753eb8 commit 506d5fd

File tree

57 files changed

+752
-1401
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+752
-1401
lines changed

src/Microservices/Common/ClassifiedAds.Domain/Repositories/IRepository.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using ClassifiedAds.Domain.Entities;
2+
using System;
23
using System.Collections.Generic;
34
using System.Linq;
5+
using System.Linq.Expressions;
46
using System.Threading;
57
using System.Threading.Tasks;
68

@@ -22,5 +24,15 @@ public interface IRepository<TEntity, TKey>
2224
Task<T> SingleOrDefaultAsync<T>(IQueryable<T> query);
2325

2426
Task<List<T>> ToListAsync<T>(IQueryable<T> query);
27+
28+
void BulkInsert(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>> columnNamesSelector);
29+
30+
void BulkInsert(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>> columnNamesSelector, Expression<Func<TEntity, object>> idSelector);
31+
32+
void BulkUpdate(IList<TEntity> data, Expression<Func<TEntity, object>> idSelector, Expression<Func<TEntity, object>> columnNamesSelector);
33+
34+
void BulkMerge(IEnumerable<TEntity> data, Expression<Func<TEntity, object>> idSelector, Expression<Func<TEntity, object>> updateColumnNamesSelector, Expression<Func<TEntity, object>> insertColumnNamesSelector);
35+
36+
void BulkDelete(IList<TEntity> data, Expression<Func<TEntity, object>> idSelector);
2537
}
2638
}

src/Microservices/Common/ClassifiedAds.Infrastructure/ClassifiedAds.Infrastructure.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@
3434
<PackageReference Include="Azure.Storage.Queues" Version="12.8.0" />
3535
<PackageReference Include="Castle.Core" Version="4.4.1" />
3636
<PackageReference Include="Confluent.Kafka" Version="1.8.2" />
37-
<PackageReference Include="CryptographyHelper" Version="1.0.0-beta4" />
37+
<PackageReference Include="CryptographyHelper" Version="1.0.0" />
3838
<PackageReference Include="CsvHelper" Version="27.2.0" />
3939
<PackageReference Include="Dapper.StrongName" Version="2.0.123" />
4040
<PackageReference Include="DinkToPdf" Version="1.0.8" />
4141
<PackageReference Include="Google.Protobuf" Version="3.19.1" />
4242
<PackageReference Include="Grpc.Net.Client" Version="2.40.0" />
43+
<PackageReference Include="EntityFrameworkCore.SqlServer.SimpleBulks" Version="6.0.0" />
4344
<PackageReference Include="IdentityModel" Version="5.2.0" />
4445
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.19.0" />
4546
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.0" />
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using ClassifiedAds.CrossCuttingConcerns.OS;
2+
using ClassifiedAds.Domain.Entities;
3+
using ClassifiedAds.Domain.Repositories;
4+
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkDelete;
5+
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkInsert;
6+
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkMerge;
7+
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkUpdate;
8+
using Microsoft.EntityFrameworkCore;
9+
using System;
10+
using System.Collections.Generic;
11+
using System.Linq;
12+
using System.Linq.Expressions;
13+
using System.Threading;
14+
using System.Threading.Tasks;
15+
16+
namespace ClassifiedAds.Infrastructure.Persistence
17+
{
18+
public class DbContextRepository<TDbContext, TEntity, TKey> : IRepository<TEntity, TKey>
19+
where TEntity : AggregateRoot<TKey>
20+
where TDbContext : DbContext, IUnitOfWork
21+
{
22+
private readonly TDbContext _dbContext;
23+
private readonly IDateTimeProvider _dateTimeProvider;
24+
25+
protected DbSet<TEntity> DbSet => _dbContext.Set<TEntity>();
26+
27+
public IUnitOfWork UnitOfWork
28+
{
29+
get
30+
{
31+
return _dbContext;
32+
}
33+
}
34+
35+
public DbContextRepository(TDbContext dbContext, IDateTimeProvider dateTimeProvider)
36+
{
37+
_dbContext = dbContext;
38+
_dateTimeProvider = dateTimeProvider;
39+
}
40+
41+
public async Task AddOrUpdateAsync(TEntity entity, CancellationToken cancellationToken = default)
42+
{
43+
if (entity.Id.Equals(default(TKey)))
44+
{
45+
entity.CreatedDateTime = _dateTimeProvider.OffsetNow;
46+
await DbSet.AddAsync(entity, cancellationToken);
47+
}
48+
else
49+
{
50+
entity.UpdatedDateTime = _dateTimeProvider.OffsetNow;
51+
}
52+
}
53+
54+
public void Delete(TEntity entity)
55+
{
56+
DbSet.Remove(entity);
57+
}
58+
59+
public IQueryable<TEntity> GetAll()
60+
{
61+
return _dbContext.Set<TEntity>();
62+
}
63+
64+
public Task<T1> FirstOrDefaultAsync<T1>(IQueryable<T1> query)
65+
{
66+
return query.FirstOrDefaultAsync();
67+
}
68+
69+
public Task<T1> SingleOrDefaultAsync<T1>(IQueryable<T1> query)
70+
{
71+
return query.SingleOrDefaultAsync();
72+
}
73+
74+
public Task<List<T1>> ToListAsync<T1>(IQueryable<T1> query)
75+
{
76+
return query.ToListAsync();
77+
}
78+
79+
public void BulkInsert(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>> columnNamesSelector)
80+
{
81+
_dbContext.BulkInsert(entities, columnNamesSelector);
82+
}
83+
84+
public void BulkInsert(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>> columnNamesSelector, Expression<Func<TEntity, object>> idSelector)
85+
{
86+
_dbContext.BulkInsert(entities, columnNamesSelector, idSelector);
87+
}
88+
89+
public void BulkUpdate(IList<TEntity> data, Expression<Func<TEntity, object>> idSelector, Expression<Func<TEntity, object>> columnNamesSelector)
90+
{
91+
_dbContext.BulkUpdate(data, idSelector, columnNamesSelector);
92+
}
93+
94+
public void BulkDelete(IList<TEntity> data, Expression<Func<TEntity, object>> idSelector)
95+
{
96+
_dbContext.BulkDelete(data, idSelector);
97+
}
98+
99+
public void BulkMerge(IEnumerable<TEntity> data, Expression<Func<TEntity, object>> idSelector, Expression<Func<TEntity, object>> updateColumnNamesSelector, Expression<Func<TEntity, object>> insertColumnNamesSelector)
100+
{
101+
_dbContext.BulkMerge(data, idSelector, updateColumnNamesSelector, insertColumnNamesSelector);
102+
}
103+
}
104+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using ClassifiedAds.Domain.Repositories;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore.Storage;
4+
using System;
5+
using System.Data;
6+
using System.Reflection;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
10+
namespace ClassifiedAds.Infrastructure.Persistence
11+
{
12+
public class DbContextUnitOfWork<TDbContext> : DbContext, IUnitOfWork
13+
where TDbContext : DbContext
14+
{
15+
private IDbContextTransaction _dbContextTransaction;
16+
17+
public DbContextUnitOfWork(DbContextOptions<TDbContext> options)
18+
: base(options)
19+
{
20+
}
21+
22+
public IDisposable BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
23+
{
24+
_dbContextTransaction = Database.BeginTransaction(isolationLevel);
25+
return _dbContextTransaction;
26+
}
27+
28+
public async Task<IDisposable> BeginTransactionAsync(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted, CancellationToken cancellationToken = default)
29+
{
30+
_dbContextTransaction = await Database.BeginTransactionAsync(isolationLevel, cancellationToken);
31+
return _dbContextTransaction;
32+
}
33+
34+
public void CommitTransaction()
35+
{
36+
_dbContextTransaction.Commit();
37+
}
38+
39+
public async Task CommitTransactionAsync(CancellationToken cancellationToken = default)
40+
{
41+
await _dbContextTransaction.CommitAsync(cancellationToken);
42+
}
43+
44+
protected override void OnModelCreating(ModelBuilder builder)
45+
{
46+
base.OnModelCreating(builder);
47+
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
48+
}
49+
}
50+
}
Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

3-
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
5-
<CodeAnalysisRuleSet>ClassifiedAds.ruleset</CodeAnalysisRuleSet>
6-
</PropertyGroup>
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<CodeAnalysisRuleSet>ClassifiedAds.ruleset</CodeAnalysisRuleSet>
6+
</PropertyGroup>
77

8-
<ItemGroup>
9-
<FrameworkReference Include="Microsoft.AspNetCore.App" />
10-
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
11-
<PrivateAssets>all</PrivateAssets>
12-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13-
</PackageReference>
14-
</ItemGroup>
8+
<ItemGroup>
9+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
10+
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0">
11+
<PrivateAssets>all</PrivateAssets>
12+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13+
</PackageReference>
14+
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
15+
<PrivateAssets>all</PrivateAssets>
16+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17+
</PackageReference>
18+
</ItemGroup>
1519

16-
<ItemGroup>
17-
<ProjectReference Include="..\..\Common\ClassifiedAds.Application\ClassifiedAds.Application.csproj" />
18-
<ProjectReference Include="..\..\Common\ClassifiedAds.CrossCuttingConcerns\ClassifiedAds.CrossCuttingConcerns.csproj" />
19-
<ProjectReference Include="..\..\Common\ClassifiedAds.Domain\ClassifiedAds.Domain.csproj" />
20-
<ProjectReference Include="..\..\Common\ClassifiedAds.Infrastructure\ClassifiedAds.Infrastructure.csproj" />
21-
<ProjectReference Include="..\ClassifiedAds.Services.AuditLog\ClassifiedAds.Services.AuditLog.csproj" />
22-
</ItemGroup>
20+
<ItemGroup>
21+
<ProjectReference Include="..\..\Common\ClassifiedAds.Application\ClassifiedAds.Application.csproj" />
22+
<ProjectReference Include="..\..\Common\ClassifiedAds.CrossCuttingConcerns\ClassifiedAds.CrossCuttingConcerns.csproj" />
23+
<ProjectReference Include="..\..\Common\ClassifiedAds.Domain\ClassifiedAds.Domain.csproj" />
24+
<ProjectReference Include="..\..\Common\ClassifiedAds.Infrastructure\ClassifiedAds.Infrastructure.csproj" />
25+
<ProjectReference Include="..\ClassifiedAds.Services.AuditLog\ClassifiedAds.Services.AuditLog.csproj" />
26+
</ItemGroup>
2327

2428
</Project>

src/Microservices/Services.AuditLog/ClassifiedAds.Services.AuditLog.Api/Startup.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.Extensions.Hosting;
1111
using Polly;
1212
using System;
13+
using System.Reflection;
1314

1415
namespace ClassifiedAds.Services.AuditLog
1516
{
@@ -31,6 +32,8 @@ public Startup(IConfiguration configuration, IWebHostEnvironment env)
3132
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
3233
public void ConfigureServices(IServiceCollection services)
3334
{
35+
AppSettings.ConnectionStrings.MigrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
36+
3437
services.AddControllers(configure =>
3538
{
3639
configure.Filters.Add(typeof(GlobalExceptionFilter));

src/Microservices/Services.AuditLog/ClassifiedAds.Services.AuditLog/ClassifiedAds.Services.AuditLog.csproj

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net6.0</TargetFramework>
@@ -17,10 +17,6 @@
1717
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
1818
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
1919
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
20-
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0">
21-
<PrivateAssets>all</PrivateAssets>
22-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
23-
</PackageReference>
2420
<PackageReference Include="Polly" Version="7.2.2" />
2521
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
2622
<PrivateAssets>all</PrivateAssets>

src/Microservices/Services.AuditLog/ClassifiedAds.Services.AuditLog/Repositories/AuditLogDbContext.cs

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,16 @@
1-
using ClassifiedAds.Domain.Repositories;
1+
using ClassifiedAds.Infrastructure.Persistence;
22
using Microsoft.EntityFrameworkCore;
3-
using Microsoft.EntityFrameworkCore.Storage;
4-
using System;
5-
using System.Data;
63
using System.Reflection;
7-
using System.Threading;
8-
using System.Threading.Tasks;
94

105
namespace ClassifiedAds.Services.AuditLog.Repositories
116
{
12-
public class AuditLogDbContext : DbContext, IUnitOfWork
7+
public class AuditLogDbContext : DbContextUnitOfWork<AuditLogDbContext>
138
{
14-
private IDbContextTransaction _dbContextTransaction;
15-
169
public AuditLogDbContext(DbContextOptions<AuditLogDbContext> options)
1710
: base(options)
1811
{
1912
}
2013

21-
public IDisposable BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
22-
{
23-
_dbContextTransaction = Database.BeginTransaction(isolationLevel);
24-
return _dbContextTransaction;
25-
}
26-
27-
public async Task<IDisposable> BeginTransactionAsync(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted, CancellationToken cancellationToken = default)
28-
{
29-
_dbContextTransaction = await Database.BeginTransactionAsync(isolationLevel, cancellationToken);
30-
return _dbContextTransaction;
31-
}
32-
33-
public void CommitTransaction()
34-
{
35-
_dbContextTransaction.Commit();
36-
}
37-
38-
public async Task CommitTransactionAsync(CancellationToken cancellationToken = default)
39-
{
40-
await _dbContextTransaction.CommitAsync(cancellationToken);
41-
}
42-
4314
protected override void OnModelCreating(ModelBuilder builder)
4415
{
4516
base.OnModelCreating(builder);

0 commit comments

Comments
 (0)