Skip to content

Commit 54597cb

Browse files
authored
Merge pull request #3 from msx752/development
Development
2 parents d5ad13a + 9f4134b commit 54597cb

File tree

8 files changed

+206
-24
lines changed

8 files changed

+206
-24
lines changed

src/SampleDotnet.RepositoryFactory/Interfaces/IRepository.cs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
namespace SampleDotnet.RepositoryFactory.Interfaces;
22

3-
public interface IRepository<TDbContext> : IDisposable
4-
where TDbContext : DbContext
3+
public interface IRepository : IDisposable
54
{
6-
DatabaseFacade Database { get; }
5+
DatabaseFacade Database => CurrentDbContext.Database;
6+
Type DbContextType => CurrentDbContext.GetType();
7+
8+
protected abstract DbContext CurrentDbContext { get; }
9+
10+
int SaveChanges();
711

12+
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
13+
}
14+
15+
public interface IRepository<TDbContext> : IRepository
16+
where TDbContext : DbContext
17+
{
818
IQueryable<T> AsQueryable<T>() where T : class;
919

1020
void Delete<T>(T entity) where T : class;
@@ -15,17 +25,27 @@ public interface IRepository<TDbContext> : IDisposable
1525

1626
T? Find<T>(params object[] keyValues) where T : class;
1727

28+
ValueTask<T?> FindAsync<T>(object[] keyValues, CancellationToken cancellationToken = default) where T : class;
29+
1830
T? FirstOrDefault<T>(Expression<Func<T, bool>> predicate) where T : class;
1931

32+
Task<T?> FirstOrDefaultAsync<T>(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) where T : class;
33+
2034
T? GetById<T>(object id) where T : class;
2135

36+
ValueTask<T?> GetByIdAsync<T>(object id, CancellationToken cancellationToken = default) where T : class;
37+
2238
void Insert<T>(T entity) where T : class;
2339

2440
void Insert<T>(params T[] entities) where T : class;
2541

2642
void Insert<T>(IEnumerable<T> entities) where T : class;
2743

28-
int SaveChanges();
44+
ValueTask<EntityEntry<T>> InsertAsync<T>(T entity, CancellationToken cancellationToken = default) where T : class;
45+
46+
Task InsertAsync<T>(IEnumerable<T> entities, CancellationToken cancellationToken = default) where T : class;
47+
48+
Task InsertAsync<T>(T[] entities, CancellationToken cancellationToken = default) where T : class;
2949

3050
void Update<T>(T entity) where T : class;
3151

src/SampleDotnet.RepositoryFactory/Repository.cs

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@ public class Repository<TDbContext>
77
private readonly TDbContext _context;
88
private bool disposedValue;
99

10-
public DatabaseFacade Database { get => _context.Database; }
11-
1210
public Repository(TDbContext dbContext)
1311
{
1412
_context = dbContext;
1513
}
1614

15+
public DbContext CurrentDbContext => _context;
16+
1717
public IQueryable<T> AsQueryable<T>() where T : class
1818
{
19-
return _context.Set<T>().AsQueryable<T>();
19+
return CurrentDbContext.Set<T>().AsQueryable<T>();
2020
}
2121

2222
public void Delete<T>(T entity) where T : class
2323
{
24-
var entry = _context.Entry(entity);
24+
var entry = CurrentDbContext.Entry(entity);
2525
entry.State = EntityState.Deleted;
2626
}
2727

@@ -45,7 +45,12 @@ public void Dispose()
4545

4646
public T? Find<T>(params object[] keyValues) where T : class
4747
{
48-
return _context.Set<T>().Find(keyValues);
48+
return CurrentDbContext.Set<T>().Find(keyValues);
49+
}
50+
51+
public ValueTask<T?> FindAsync<T>(object[] keyValues, CancellationToken cancellationToken = default) where T : class
52+
{
53+
return CurrentDbContext.Set<T>().FindAsync(keyValues, cancellationToken);
4954
}
5055

5156
public T? FirstOrDefault<T>(Expression<Func<T, bool>> predicate) where T : class
@@ -54,22 +59,33 @@ public void Dispose()
5459
return query.FirstOrDefault(predicate);
5560
}
5661

62+
public Task<T?> FirstOrDefaultAsync<T>(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) where T : class
63+
{
64+
IQueryable<T> query = AsQueryable<T>();
65+
return query.FirstOrDefaultAsync(predicate, cancellationToken);
66+
}
67+
5768
public T? GetById<T>(object id) where T : class
5869
{
5970
return Find<T>(id);
6071
}
6172

73+
public ValueTask<T?> GetByIdAsync<T>(object id, CancellationToken cancellationToken = default) where T : class
74+
{
75+
return FindAsync<T>(new object[] { id }, cancellationToken);
76+
}
77+
6278
public void Insert<T>(T entity) where T : class
6379
{
6480
if (entity is IHasDateTimeOffset dt)
6581
dt.CreatedAt = DateTimeOffset.Now;
6682

67-
_context.Set<T>().Add(entity);
83+
CurrentDbContext.Set<T>().Add(entity);
6884
}
6985

7086
public void Insert<T>(params T[] entities) where T : class
7187
{
72-
_context.Set<T>().AddRange(entities.Select(f =>
88+
CurrentDbContext.Set<T>().AddRange(entities.Select(f =>
7389
{
7490
if (f is IHasDateTimeOffset dt)
7591
dt.CreatedAt = DateTimeOffset.Now;
@@ -80,7 +96,7 @@ public void Insert<T>(params T[] entities) where T : class
8096

8197
public void Insert<T>(IEnumerable<T> entities) where T : class
8298
{
83-
_context.Set<T>().AddRange(entities.Select(f =>
99+
CurrentDbContext.Set<T>().AddRange(entities.Select(f =>
84100
{
85101
if (f is IHasDateTimeOffset dt)
86102
dt.CreatedAt = DateTimeOffset.Now;
@@ -89,15 +105,51 @@ public void Insert<T>(IEnumerable<T> entities) where T : class
89105
}));
90106
}
91107

108+
public ValueTask<EntityEntry<T>> InsertAsync<T>(T entity, CancellationToken cancellationToken = default) where T : class
109+
{
110+
if (entity is IHasDateTimeOffset dt)
111+
dt.CreatedAt = DateTimeOffset.Now;
112+
113+
return CurrentDbContext.Set<T>().AddAsync(entity, cancellationToken);
114+
}
115+
116+
public Task InsertAsync<T>(T[] entities, CancellationToken cancellationToken = default) where T : class
117+
{
118+
return CurrentDbContext.Set<T>().AddRangeAsync(entities.Select(f =>
119+
{
120+
if (f is IHasDateTimeOffset dt)
121+
dt.CreatedAt = DateTimeOffset.Now;
122+
123+
return f;
124+
}), cancellationToken);
125+
}
126+
127+
public Task InsertAsync<T>(IEnumerable<T> entities, CancellationToken cancellationToken = default) where T : class
128+
{
129+
return CurrentDbContext.Set<T>().AddRangeAsync(entities.Select(f =>
130+
{
131+
if (f is IHasDateTimeOffset dt)
132+
dt.CreatedAt = DateTimeOffset.Now;
133+
134+
return f;
135+
}), cancellationToken);
136+
}
137+
92138
public int SaveChanges()
93139
{
94-
var result = _context.SaveChanges();
140+
var result = CurrentDbContext.SaveChanges();
141+
return result;
142+
}
143+
144+
public Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
145+
{
146+
var result = CurrentDbContext.SaveChangesAsync(cancellationToken);
95147
return result;
96148
}
97149

98150
public void Update<T>(T entity) where T : class
99151
{
100-
var entry = _context.Entry(entity);
152+
var entry = CurrentDbContext.Entry(entity);
101153
entry.State = EntityState.Modified;
102154

103155
if (entry.Entity is IHasDateTimeOffset dt)
@@ -127,7 +179,13 @@ protected virtual void Dispose(bool disposing)
127179
{
128180
if (disposing)
129181
{
130-
_context.Dispose();
182+
try
183+
{
184+
CurrentDbContext.Dispose();
185+
}
186+
catch
187+
{
188+
}
131189
}
132190

133191
disposedValue = true;

src/SampleDotnet.RepositoryFactory/SampleDotnet.RepositoryFactory.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
<ContinuousIntegrationBuild>True</ContinuousIntegrationBuild>
3232
<EmbedUntrackedSources>True</EmbedUntrackedSources>
3333
<Copyright>Copyright 2023</Copyright>
34-
<AssemblyVersion>2.0.0</AssemblyVersion>
35-
<Version>2.0.0</Version>
34+
<AssemblyVersion>2.1.0</AssemblyVersion>
35+
<Version>2.1.0</Version>
3636
</PropertyGroup>
3737

3838
<ItemGroup>

src/SampleDotnet.RepositoryFactory/_GlobalUsings.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
global using SampleDotnet.RepositoryFactory;
44
global using SampleDotnet.RepositoryFactory.Interfaces;
55
global using System.Data;
6-
global using System.Linq.Expressions;
6+
global using System.Linq.Expressions;
7+
global using Microsoft.EntityFrameworkCore.ChangeTracking;
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
namespace SampleDotnet.RepositoryFactory.Tests.Cases;
2+
3+
public class DateTimeOffsetAsyncTests
4+
{
5+
public DateTimeOffsetAsyncTests()
6+
{
7+
}
8+
9+
[Fact]
10+
public async Task Case_set_CreatedAt_DateTimeOffsetAsync()
11+
{
12+
IHostBuilder host = Host.CreateDefaultBuilder().ConfigureServices((services) =>
13+
{
14+
services.AddDbContextFactory<TestApplicationDbContext>(options =>
15+
options.UseInMemoryDatabase("Case_set_CreatedAt_DateTimeOffset"));
16+
});
17+
18+
IHost b = host.Build();
19+
20+
//scope1
21+
using (IServiceScope scope = b.Services.CreateScope())
22+
using (var cancellationTokenSource = new CancellationTokenSource())
23+
{
24+
IDbContextFactory<TestApplicationDbContext> dbcontext = scope.ServiceProvider.GetRequiredService<IDbContextFactory<TestApplicationDbContext>>();
25+
using (IRepository<TestApplicationDbContext> repo = dbcontext.CreateRepository())
26+
{
27+
TestUserEntity userEntity = new();
28+
userEntity.Name = "TestName";
29+
userEntity.Surname = "TestSurname";
30+
31+
await repo.InsertAsync(userEntity, cancellationTokenSource.Token);
32+
await ((IRepository)repo).SaveChangesAsync(cancellationTokenSource.Token);
33+
34+
userEntity.CreatedAt.ShouldNotBeNull();
35+
}
36+
}
37+
}
38+
39+
[Fact]
40+
public async Task Case_set_UpdatedAt_DateTimeOffsettAsync()
41+
{
42+
IHostBuilder host = Host.CreateDefaultBuilder().ConfigureServices((services) =>
43+
{
44+
services.AddDbContextFactory<TestApplicationDbContext>(options =>
45+
options.UseInMemoryDatabase("Case_set_UpdatedAt_DateTimeOffset"));
46+
});
47+
48+
IHost b = host.Build();
49+
50+
//scope1
51+
using (IServiceScope scope = b.Services.CreateScope())
52+
using (var cancellationTokenSource = new CancellationTokenSource())
53+
{
54+
IDbContextFactory<TestApplicationDbContext> dbcontext = scope.ServiceProvider.GetRequiredService<IDbContextFactory<TestApplicationDbContext>>();
55+
using (IRepository<TestApplicationDbContext> repo = dbcontext.CreateRepository())
56+
{
57+
TestUserEntity userEntity = new();
58+
userEntity.Name = "TestName";
59+
userEntity.Surname = "TestSurname";
60+
61+
userEntity.CreatedAt.ShouldBeNull();
62+
userEntity.UpdatedAt.ShouldBeNull();
63+
64+
await repo.InsertAsync(userEntity, cancellationTokenSource.Token);
65+
await ((IRepository)repo).SaveChangesAsync(cancellationTokenSource.Token);
66+
67+
userEntity.CreatedAt.ShouldNotBeNull();
68+
userEntity.UpdatedAt.ShouldBeNull();
69+
}
70+
}
71+
72+
//scope2
73+
using (IServiceScope scope = b.Services.CreateScope())
74+
using (var cancellationTokenSource = new CancellationTokenSource())
75+
{
76+
IDbContextFactory<TestApplicationDbContext> dbcontext = scope.ServiceProvider.GetRequiredService<IDbContextFactory<TestApplicationDbContext>>();
77+
using (IRepository<TestApplicationDbContext> repo = dbcontext.CreateRepository())
78+
{
79+
TestUserEntity? userEntity = await repo.FirstOrDefaultAsync<TestUserEntity>(f => f.Name == "TestName" && f.Surname == "TestSurname", cancellationTokenSource.Token);
80+
81+
userEntity.ShouldNotBeNull();
82+
userEntity.CreatedAt.ShouldNotBeNull();
83+
userEntity.UpdatedAt.ShouldBeNull();
84+
85+
repo.Update(userEntity);
86+
await ((IRepository)repo).SaveChangesAsync(cancellationTokenSource.Token);
87+
88+
userEntity.CreatedAt.ShouldNotBeNull();
89+
userEntity.UpdatedAt.ShouldNotBeNull();
90+
}
91+
}
92+
}
93+
}

test/SampleDotnet.RepositoryFactory.Tests/Cases/DateTimeOffsetTests.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ public void Case_set_CreatedAt_DateTimeOffset()
2323
IDbContextFactory<TestApplicationDbContext> dbcontext = scope.ServiceProvider.GetRequiredService<IDbContextFactory<TestApplicationDbContext>>();
2424
using (IRepository<TestApplicationDbContext> repo = dbcontext.CreateRepository())
2525
{
26-
TestUserEntity userEntity = new TestUserEntity();
26+
TestUserEntity userEntity = new();
2727
userEntity.Name = "TestName";
2828
userEntity.Surname = "TestSurname";
2929

3030
repo.Insert(userEntity);
31-
repo.SaveChanges();
31+
((IRepository)repo).SaveChanges();
3232

3333
userEntity.CreatedAt.ShouldNotBeNull();
3434
}
@@ -52,30 +52,35 @@ public void Case_set_UpdatedAt_DateTimeOffset()
5252
IDbContextFactory<TestApplicationDbContext> dbcontext = scope.ServiceProvider.GetRequiredService<IDbContextFactory<TestApplicationDbContext>>();
5353
using (IRepository<TestApplicationDbContext> repo = dbcontext.CreateRepository())
5454
{
55-
TestUserEntity userEntity = new TestUserEntity();
55+
TestUserEntity userEntity = new();
5656
userEntity.Name = "TestName";
5757
userEntity.Surname = "TestSurname";
5858

5959
userEntity.CreatedAt.ShouldBeNull();
6060
userEntity.UpdatedAt.ShouldBeNull();
6161

6262
repo.Insert(userEntity);
63-
repo.SaveChanges();
63+
((IRepository)repo).SaveChanges();
6464

6565
userEntity.CreatedAt.ShouldNotBeNull();
6666
userEntity.UpdatedAt.ShouldBeNull();
6767
}
68+
}
6869

69-
//scope2
70+
//scope2
71+
using (IServiceScope scope = b.Services.CreateScope())
72+
{
73+
IDbContextFactory<TestApplicationDbContext> dbcontext = scope.ServiceProvider.GetRequiredService<IDbContextFactory<TestApplicationDbContext>>();
7074
using (IRepository<TestApplicationDbContext> repo = dbcontext.CreateRepository())
7175
{
7276
TestUserEntity? userEntity = repo.FirstOrDefault<TestUserEntity>(f => f.Name == "TestName" && f.Surname == "TestSurname");
7377

7478
userEntity.ShouldNotBeNull();
79+
userEntity.CreatedAt.ShouldNotBeNull();
7580
userEntity.UpdatedAt.ShouldBeNull();
7681

7782
repo.Update(userEntity);
78-
repo.SaveChanges();
83+
((IRepository)repo).SaveChanges();
7984

8085
userEntity.CreatedAt.ShouldNotBeNull();
8186
userEntity.UpdatedAt.ShouldNotBeNull();

test/SampleDotnet.RepositoryFactory.Tests/Models/TestUserEntity.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
public class TestUserEntity : IHasDateTimeOffset
44
{
5+
[Key]
6+
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
57
public Guid Id { get; set; }
8+
69
public string Name { get; set; }
710
public string Surname { get; set; }
811

test/SampleDotnet.RepositoryFactory.Tests/_GlobalUsing.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
global using SampleDotnet.RepositoryFactory.Interfaces;
55
global using SampleDotnet.RepositoryFactory.Tests.Models;
66
global using Shouldly;
7+
global using System.ComponentModel.DataAnnotations;
8+
global using System.ComponentModel.DataAnnotations.Schema;
79
global using Xunit;

0 commit comments

Comments
 (0)