Skip to content

Commit 348e3d5

Browse files
authored
Merge pull request #17 from rpaschoal/feature/cancellation-tokens
Add cancellation token overload for async methods
2 parents 2eb703b + 97dd996 commit 348e3d5

File tree

11 files changed

+261
-42
lines changed

11 files changed

+261
-42
lines changed

DynamicRepository.EF/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.3.0")]
36-
[assembly: AssemblyFileVersion("1.3.0")]
35+
[assembly: AssemblyVersion("1.2.1")]
36+
[assembly: AssemblyFileVersion("1.2.1")]

DynamicRepository.EF/Repository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public virtual Entity Get(Key key)
8181
queriedEntity = DbSet.Find(key);
8282
}
8383

84-
return GlobalFilter != null ? new[] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
84+
return GlobalFilter != null && queriedEntity != null ? new[] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
8585
}
8686

8787
/// <summary>
@@ -103,7 +103,7 @@ public virtual async Task<Entity> GetAsync(Key key)
103103
queriedEntity = await DbSet.FindAsync(key);
104104
}
105105

106-
return GlobalFilter != null ? await new[] { queriedEntity }.AsQueryable().FirstOrDefaultAsync(GlobalFilter) : queriedEntity;
106+
return GlobalFilter != null && queriedEntity != null ? await new[] { queriedEntity }.AsQueryable().FirstOrDefaultAsync(GlobalFilter) : queriedEntity;
107107
}
108108

109109
/// <summary>

DynamicRepository.EFCore/DynamicRepository.EFCore.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.1</TargetFramework>
5-
<Version>1.3.0</Version>
5+
<Version>1.3.2</Version>
66
<Authors>Rafael Carvalho</Authors>
77
<PackageProjectUrl>https://github.com/rpaschoal/DynamicRepository</PackageProjectUrl>
8+
<Description>Dynamic repository with many built-in data access methods for Repository Pattern implementation for .NET projects using EF6, EF Core or MongoDB.</Description>
89
</PropertyGroup>
910

1011
<ItemGroup>
11-
<PackageReference Include="DynamicRepository" Version="1.3.0" />
12+
<PackageReference Include="DynamicRepository" Version="1.3.2" />
1213
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
1314
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.22" />
1415
</ItemGroup>

DynamicRepository.EFCore/Repository.cs

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,40 @@ public virtual Entity Get(Key key)
8080
queriedEntity = DbSet.Find(key);
8181
}
8282

83-
return GlobalFilter != null ? new[] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
83+
return GlobalFilter != null && queriedEntity != null ? new[] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
8484
}
8585

8686
/// <summary>
8787
/// Gets an entity instance based on its <see cref="Key"/>.
8888
/// </summary>
8989
/// <param name="key">The desired entity key value.</param>
9090
/// <returns>Persisted entity if found, otherwise NULL.</returns>
91-
public virtual async Task<Entity> GetAsync(Key key)
91+
public virtual Task<Entity> GetAsync(Key key)
92+
{
93+
return GetAsync(key, CancellationToken.None);
94+
}
95+
96+
/// <summary>
97+
/// Gets an entity instance based on its <see cref="Key"/>.
98+
/// </summary>
99+
/// <param name="key">The desired entity key value.</param>
100+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
101+
/// <returns>Persisted entity if found, otherwise NULL.</returns>
102+
public virtual async Task<Entity> GetAsync(Key key, CancellationToken cancellationToken)
92103
{
93104
Entity queriedEntity;
94105

95106
if (key is Array)
96107
{
97108
// This is to handle entity framework find by composite key
98-
queriedEntity = await DbSet.FindAsync((key as IEnumerable).Cast<object>().ToArray());
109+
queriedEntity = await DbSet.FindAsync((key as IEnumerable).Cast<object>().ToArray(), cancellationToken: cancellationToken);
99110
}
100111
else
101112
{
102-
queriedEntity = await DbSet.FindAsync(key);
113+
queriedEntity = await DbSet.FindAsync(new object[] { key }, cancellationToken: cancellationToken);
103114
}
104115

105-
return GlobalFilter != null ? await new[] { queriedEntity }.AsQueryable().FirstOrDefaultAsync(GlobalFilter) : queriedEntity;
116+
return GlobalFilter != null && queriedEntity != null ? await new[] { queriedEntity }.AsQueryable().FirstOrDefaultAsync(GlobalFilter) : queriedEntity;
106117
}
107118

108119
/// <summary>
@@ -120,8 +131,17 @@ public virtual void Insert(Entity entity)
120131
/// <param name="entity">The new <see cref="Entity"/> instance to be persisted.</param>
121132
public virtual Task InsertAsync(Entity entity)
122133
{
123-
// TODO: Cancellation tokens will be implement soon with another PR
124-
return DbSet.AddAsync(entity, CancellationToken.None).AsTask();
134+
return InsertAsync(entity, CancellationToken.None);
135+
}
136+
137+
/// <summary>
138+
/// Persists a new entity model.
139+
/// </summary>
140+
/// <param name="entity">The new <see cref="Entity"/> instance to be persisted.</param>
141+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
142+
public virtual Task InsertAsync(Entity entity, CancellationToken cancellationToken)
143+
{
144+
return DbSet.AddAsync(entity, cancellationToken).AsTask();
125145
}
126146

127147
/// <summary>
@@ -138,6 +158,16 @@ public virtual void Update(Entity entityToUpdate)
138158
/// </summary>
139159
/// <param name="entityToUpdate">The <see cref="Entity"/> instance to be updated.</param>
140160
public virtual Task UpdateAsync(Entity entityToUpdate)
161+
{
162+
return UpdateAsync(entityToUpdate, CancellationToken.None);
163+
}
164+
165+
/// <summary>
166+
/// Updates an existing persisted entity.
167+
/// </summary>
168+
/// <param name="entityToUpdate">The <see cref="Entity"/> instance to be updated.</param>
169+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
170+
public virtual Task UpdateAsync(Entity entityToUpdate, CancellationToken cancellationToken)
141171
{
142172
return Task.Run(() => Context.Entry(entityToUpdate).State = EntityState.Modified);
143173
}
@@ -157,7 +187,17 @@ public virtual void Delete(Key id)
157187
/// <param name="id">The primary key of the <see cref="Entity"/> to be deleted.</param>
158188
public virtual async Task DeleteAsync(Key id)
159189
{
160-
await DeleteAsync(await GetAsync(id));
190+
await DeleteAsync(id, CancellationToken.None);
191+
}
192+
193+
/// <summary>
194+
/// Deletes an existing entity.
195+
/// </summary>
196+
/// <param name="id">The primary key of the <see cref="Entity"/> to be deleted.</param>
197+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
198+
public virtual async Task DeleteAsync(Key id, CancellationToken cancellationToken)
199+
{
200+
await DeleteAsync(await GetAsync(id, cancellationToken), cancellationToken);
161201
}
162202

163203
/// <summary>
@@ -177,6 +217,16 @@ public void Delete(Entity entityToDelete)
177217
/// </summary>
178218
/// <param name="entityToDelete">The <see cref="Entity"/> instance to be deleted.</param>
179219
public Task DeleteAsync(Entity entityToDelete)
220+
{
221+
return DeleteAsync(entityToDelete, CancellationToken.None);
222+
}
223+
224+
/// <summary>
225+
/// Deletes an existing entity.
226+
/// </summary>
227+
/// <param name="entityToDelete">The <see cref="Entity"/> instance to be deleted.</param>
228+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
229+
public Task DeleteAsync(Entity entityToDelete, CancellationToken cancellationToken)
180230
{
181231
if (entityToDelete != null)
182232
{

DynamicRepository.MongoDB/DynamicRepository.MongoDB.csproj

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

33
<PropertyGroup>
44
<TargetFramework>netstandard2.1</TargetFramework>
5-
<Version>1.3.0</Version>
5+
<Version>1.3.2</Version>
66
<Authors>Rafael Carvalho</Authors>
7-
<Description></Description>
7+
<Description>Dynamic repository with many built-in data access methods for Repository Pattern implementation for .NET projects using EF6, EF Core or MongoDB.</Description>
88
<PackageProjectUrl>https://github.com/rpaschoal/DynamicRepository</PackageProjectUrl>
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="DynamicRepository" Version="1.3.0" />
12+
<PackageReference Include="DynamicRepository" Version="1.3.2" />
1313
<PackageReference Include="MongoDB.Driver" Version="2.10.2" />
1414
<PackageReference Include="MongoDB.Driver.Core" Version="2.10.2" />
1515
</ItemGroup>

DynamicRepository.MongoDB/MongoDBRepository.cs

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.Linq;
77
using System.Linq.Expressions;
8+
using System.Threading;
89
using System.Threading.Tasks;
910

1011
namespace DynamicRepository.MongoDB
@@ -136,19 +137,30 @@ public Entity Get(Key id)
136137
{
137138
var queriedEntity = Collection.Find(GetIdFilter(id)).FirstOrDefault();
138139

139-
return GlobalFilter != null ? new[] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
140+
return GlobalFilter != null && queriedEntity != null ? new[] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
140141
}
141142

142143
/// <summary>
143144
/// Gets an entity instance based on its <see cref="Key"/>.
144145
/// </summary>
145146
/// <param name="key">The desired entity key value.</param>
146147
/// <returns>Persisted entity if found, otherwise NULL.</returns>
147-
public async Task<Entity> GetAsync(Key id)
148+
public Task<Entity> GetAsync(Key id)
148149
{
149-
var queriedEntity = await (await Collection.FindAsync(GetIdFilter(id))).FirstOrDefaultAsync();
150+
return GetAsync(id, CancellationToken.None);
151+
}
150152

151-
return GlobalFilter != null ? new [] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
153+
/// <summary>
154+
/// Gets an entity instance based on its <see cref="Key"/>.
155+
/// </summary>
156+
/// <param name="key">The desired entity key value.</param>
157+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
158+
/// <returns>Persisted entity if found, otherwise NULL.</returns>
159+
public async Task<Entity> GetAsync(Key id, CancellationToken cancellationToken)
160+
{
161+
var queriedEntity = await (await Collection.FindAsync(GetIdFilter(id), cancellationToken: cancellationToken)).FirstOrDefaultAsync();
162+
163+
return GlobalFilter != null && queriedEntity != null ? new[] { queriedEntity }.AsQueryable().FirstOrDefault(GlobalFilter) : queriedEntity;
152164
}
153165

154166
/// <summary>
@@ -166,7 +178,17 @@ public void Insert(Entity entity)
166178
/// <param name="entity">The new <see cref="Entity"/> instance to be persisted.</param>
167179
public Task InsertAsync(Entity entity)
168180
{
169-
return Collection.InsertOneAsync(entity);
181+
return InsertAsync(entity, CancellationToken.None);
182+
}
183+
184+
/// <summary>
185+
/// Persists a new entity model.
186+
/// </summary>
187+
/// <param name="entity">The new <see cref="Entity"/> instance to be persisted.</param>
188+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
189+
public Task InsertAsync(Entity entity, CancellationToken cancellationToken)
190+
{
191+
return Collection.InsertOneAsync(entity, null, cancellationToken);
170192
}
171193

172194
/// <summary>
@@ -184,7 +206,17 @@ public void Update(Entity entityToUpdate)
184206
/// <param name="entityToUpdate">The <see cref="Entity"/> instance to be updated.</param>
185207
public Task UpdateAsync(Entity entityToUpdate)
186208
{
187-
return Collection.ReplaceOneAsync(GetIdFilter(entityToUpdate), entityToUpdate);
209+
return UpdateAsync(entityToUpdate, CancellationToken.None);
210+
}
211+
212+
/// <summary>
213+
/// Updates an existing persisted entity.
214+
/// </summary>
215+
/// <param name="entityToUpdate">The <see cref="Entity"/> instance to be updated.</param>
216+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
217+
public Task UpdateAsync(Entity entityToUpdate, CancellationToken cancellationToken)
218+
{
219+
return Collection.ReplaceOneAsync(GetIdFilter(entityToUpdate), entityToUpdate, cancellationToken: cancellationToken);
188220
}
189221

190222
/// <summary>
@@ -202,7 +234,17 @@ public void Delete(Key id)
202234
/// <param name="id">The primary key of the <see cref="Entity"/> to be deleted.</param>
203235
public Task DeleteAsync(Key id)
204236
{
205-
return Collection.DeleteOneAsync(GetIdFilter(id));
237+
return DeleteAsync(id, CancellationToken.None);
238+
}
239+
240+
/// <summary>
241+
/// Deletes an existing entity.
242+
/// </summary>
243+
/// <param name="id">The primary key of the <see cref="Entity"/> to be deleted.</param>
244+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
245+
public Task DeleteAsync(Key id, CancellationToken cancellationToken)
246+
{
247+
return Collection.DeleteOneAsync(GetIdFilter(id), cancellationToken);
206248
}
207249

208250
/// <summary>
@@ -220,7 +262,17 @@ public void Delete(Entity entityToDelete)
220262
/// <param name="entityToDelete">The <see cref="Entity"/> instance to be deleted.</param>
221263
public Task DeleteAsync(Entity entityToDelete)
222264
{
223-
return Collection.DeleteOneAsync(GetIdFilter(entityToDelete));
265+
return DeleteAsync(entityToDelete, CancellationToken.None);
266+
}
267+
268+
/// <summary>
269+
/// Deletes an existing entity.
270+
/// </summary>
271+
/// <param name="entityToDelete">The <see cref="Entity"/> instance to be deleted.</param>
272+
/// <param name="cancellationToken">A token used for cancelling propagation.</param>
273+
public Task DeleteAsync(Entity entityToDelete, CancellationToken cancellationToken)
274+
{
275+
return Collection.DeleteOneAsync(GetIdFilter(entityToDelete), cancellationToken);
224276
}
225277

226278
/// <summary>

DynamicRepository.Tests/AddOn/ResilientRepositoryDecoratorTests.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using FluentAssertions;
55
using Moq;
66
using System;
7+
using System.Threading;
78
using System.Threading.Tasks;
89
using Xunit;
910

@@ -68,7 +69,7 @@ public void ShouldBeResilientOnDeleteByIdAsync()
6869
var testKey = 1;
6970

7071
_repositoryInternalsMock
71-
.Setup(x => x.DeleteAsync(testKey))
72+
.Setup(x => x.DeleteAsync(testKey, CancellationToken.None))
7273
.Throws<Exception>();
7374

7475
// Act
@@ -77,7 +78,7 @@ public void ShouldBeResilientOnDeleteByIdAsync()
7778
// Assert
7879
action.Should().Throw<Exception>();
7980

80-
_repositoryInternalsMock.Verify(x => x.DeleteAsync(testKey), Times.Exactly(NUMBER_OF_ATTEMPTS));
81+
_repositoryInternalsMock.Verify(x => x.DeleteAsync(testKey, CancellationToken.None), Times.Exactly(NUMBER_OF_ATTEMPTS));
8182
}
8283

8384
[Fact]
@@ -87,7 +88,7 @@ public void ShouldBeResilientOnDeleteByEntityAsync()
8788
var entityStub = new MockModel();
8889

8990
_repositoryInternalsMock
90-
.Setup(x => x.DeleteAsync(entityStub))
91+
.Setup(x => x.DeleteAsync(entityStub, CancellationToken.None))
9192
.Throws<Exception>();
9293

9394
// Act
@@ -96,7 +97,7 @@ public void ShouldBeResilientOnDeleteByEntityAsync()
9697
// Assert
9798
action.Should().Throw<Exception>();
9899

99-
_repositoryInternalsMock.Verify(x => x.DeleteAsync(entityStub), Times.Exactly(NUMBER_OF_ATTEMPTS));
100+
_repositoryInternalsMock.Verify(x => x.DeleteAsync(entityStub, CancellationToken.None), Times.Exactly(NUMBER_OF_ATTEMPTS));
100101
}
101102

102103
[Fact]
@@ -125,7 +126,7 @@ public void ShouldBeResilientOnGetAsync()
125126
var testKey = 1;
126127

127128
_repositoryInternalsMock
128-
.Setup(x => x.GetAsync(testKey))
129+
.Setup(x => x.GetAsync(testKey, CancellationToken.None))
129130
.Throws<Exception>();
130131

131132
// Act
@@ -134,7 +135,7 @@ public void ShouldBeResilientOnGetAsync()
134135
// Assert
135136
action.Should().Throw<Exception>();
136137

137-
_repositoryInternalsMock.Verify(x => x.GetAsync(testKey), Times.Exactly(NUMBER_OF_ATTEMPTS));
138+
_repositoryInternalsMock.Verify(x => x.GetAsync(testKey, CancellationToken.None), Times.Exactly(NUMBER_OF_ATTEMPTS));
138139
}
139140

140141
[Fact]
@@ -182,7 +183,7 @@ public void ShouldBeResilientOnInsertAsync()
182183
var entityStub = new MockModel();
183184

184185
_repositoryInternalsMock
185-
.Setup(x => x.InsertAsync(entityStub))
186+
.Setup(x => x.InsertAsync(entityStub, CancellationToken.None))
186187
.Throws<Exception>();
187188

188189
// Act
@@ -191,7 +192,7 @@ public void ShouldBeResilientOnInsertAsync()
191192
// Assert
192193
action.Should().Throw<Exception>();
193194

194-
_repositoryInternalsMock.Verify(x => x.InsertAsync(entityStub), Times.Exactly(NUMBER_OF_ATTEMPTS));
195+
_repositoryInternalsMock.Verify(x => x.InsertAsync(entityStub, CancellationToken.None), Times.Exactly(NUMBER_OF_ATTEMPTS));
195196
}
196197

197198
[Fact]
@@ -258,7 +259,7 @@ public void ShouldBeResilientOnUpdateAsync()
258259
var entityStub = new MockModel();
259260

260261
_repositoryInternalsMock
261-
.Setup(x => x.UpdateAsync(entityStub))
262+
.Setup(x => x.UpdateAsync(entityStub, CancellationToken.None))
262263
.Throws<Exception>();
263264

264265
// Act
@@ -267,7 +268,7 @@ public void ShouldBeResilientOnUpdateAsync()
267268
// Assert
268269
action.Should().Throw<Exception>();
269270

270-
_repositoryInternalsMock.Verify(x => x.UpdateAsync(entityStub), Times.Exactly(NUMBER_OF_ATTEMPTS));
271+
_repositoryInternalsMock.Verify(x => x.UpdateAsync(entityStub, CancellationToken.None), Times.Exactly(NUMBER_OF_ATTEMPTS));
271272
}
272273
}
273274
}

0 commit comments

Comments
 (0)