From 06284c44f8a7d4e770b2a807fc5049712fe5ea0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 21 Jan 2021 22:03:39 +0300 Subject: [PATCH] Update docs for async queryable usage. --- docs/en/Application-Services.md | 9 ++++--- docs/en/AspNet-Boilerplate-Migration-Guide.md | 7 +++--- ...main-Driven-Design-Implementation-Guide.md | 12 ++++++---- docs/en/Repositories.md | 24 ++++++++++++------- docs/en/Specifications.md | 6 +++-- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/docs/en/Application-Services.md b/docs/en/Application-Services.md index 7fe9825f2a..5d779ec8c9 100644 --- a/docs/en/Application-Services.md +++ b/docs/en/Application-Services.md @@ -43,12 +43,14 @@ public class Book : AggregateRoot { if (string.IsNullOrWhiteSpace(name)) { - throw new ArgumentException($"name can not be empty or white space!"); + throw new ArgumentException( + $"name can not be empty or white space!"); } if (name.Length > MaxNameLength) { - throw new ArgumentException($"name can not be longer than {MaxNameLength} chars!"); + throw new ArgumentException( + $"name can not be longer than {MaxNameLength} chars!"); } return name; @@ -349,8 +351,9 @@ public class DistrictAppService protected async override Task GetEntityByIdAsync(DistrictKey id) { + var queryable = await Repository.GetQueryableAsync(); return await AsyncQueryableExecuter.FirstOrDefaultAsync( - Repository.Where(d => d.CityId == id.CityId && d.Name == id.Name) + queryable.Where(d => d.CityId == id.CityId && d.Name == id.Name) ); } } diff --git a/docs/en/AspNet-Boilerplate-Migration-Guide.md b/docs/en/AspNet-Boilerplate-Migration-Guide.md index f4c2ec712b..52a2fced6a 100644 --- a/docs/en/AspNet-Boilerplate-Migration-Guide.md +++ b/docs/en/AspNet-Boilerplate-Migration-Guide.md @@ -184,7 +184,7 @@ public class PersonAppService : ApplicationService, IPersonAppService } ```` -ABP Framework's repository doesn't have this method. Instead, it implements the `IQueryable` itself. So, you can directly use LINQ on the repository: +ABP Framework's repository have `GetQueryableAsync` instead: ````csharp public class PersonAppService : ApplicationService, IPersonAppService @@ -198,14 +198,15 @@ public class PersonAppService : ApplicationService, IPersonAppService public async Task DoIt() { - var people = await _personRepository + var queryable = await _personRepository.GetQueryableAsync(); + var people = await queryable .Where(p => p.BirthYear > 2000) //Use LINQ extension methods .ToListAsync(); } } ```` -> Note that in order to use the async LINQ extension methods (like `ToListAsync` here), you may need to depend on the database provider (like EF Core) since these methods are defined in the database provider package, they are not standard LINQ methods. +> Note that in order to use the async LINQ extension methods (like `ToListAsync` here), you may need to depend on the database provider (like EF Core) since these methods are defined in the database provider package, they are not standard LINQ methods. See the [repository document](Repositories.md) for alternative approaches for async query execution. #### FirstOrDefault(predicate), Single()... Methods diff --git a/docs/en/Domain-Driven-Design-Implementation-Guide.md b/docs/en/Domain-Driven-Design-Implementation-Guide.md index 9341df703b..cf2ce6bf14 100644 --- a/docs/en/Domain-Driven-Design-Implementation-Guide.md +++ b/docs/en/Domain-Driven-Design-Implementation-Guide.md @@ -754,7 +754,8 @@ namespace IssueTracking.Issues { var daysAgo30 = DateTime.Now.Subtract(TimeSpan.FromDays(30)); - return await DbSet.Where(i => + var dbSet = await GetDbSetAsync(); + return await dbSet.Where(i => //Open !i.IsClosed && @@ -906,7 +907,8 @@ public class EfCoreIssueRepository : public async Task> GetIssuesAsync(ISpecification spec) { - return await DbSet + var dbSet = await GetDbSetAsync(); + return await dbSet .Where(spec.ToExpression()) .ToListAsync(); } @@ -952,8 +954,9 @@ public class IssueAppService : ApplicationService, IIssueAppService public async Task DoItAsync() { + var queryable = await _issueRepository.GetQueryableAsync(); var issues = AsyncExecuter.ToListAsync( - _issueRepository.Where(new InActiveIssueSpecification()) + queryable.Where(new InActiveIssueSpecification()) ); } } @@ -996,8 +999,9 @@ public class IssueAppService : ApplicationService, IIssueAppService public async Task DoItAsync(Guid milestoneId) { + var queryable = await _issueRepository.GetQueryableAsync(); var issues = AsyncExecuter.ToListAsync( - _issueRepository + queryable .Where( new InActiveIssueSpecification() .And(new MilestoneSpecification(milestoneId)) diff --git a/docs/en/Repositories.md b/docs/en/Repositories.md index a2eb385094..3d0ea84821 100644 --- a/docs/en/Repositories.md +++ b/docs/en/Repositories.md @@ -222,7 +222,8 @@ public class PersonRepository : EfCoreRepository, IPe public async Task FindByNameAsync(string name) { - return await DbContext.Set() + var dbSet = await GetDbSetAsync(); + return await dbSet.Set() .Where(p => p.Name == name) .FirstOrDefaultAsync(); } @@ -235,12 +236,13 @@ You can directly access the data access provider (`DbContext` in this case) to p ## IQueryable & Async Operations -`IRepository` inherits from `IQueryable`, that means you can **directly use LINQ extension methods** on it, as shown in the example of the "*Generic Repositories*" section above. +`IRepository` provides `GetQueryableAsync()` to obtain an `IQueryable`, that means you can **directly use LINQ extension methods** on it, as shown in the example of the "*Querying / LINQ over the Repositories*" section above. **Example: Using the `Where(...)` and the `ToList()` extension methods** ````csharp -var people = _personRepository +var queryable = await _personRepository.GetQueryableAsync(); +var people = queryable .Where(p => p.Name.Contains(nameFilter)) .ToList(); ```` @@ -269,7 +271,8 @@ When you add the NuGet package to your project, you can take full power of the E **Example: Directly using the `ToListAsync()` after adding the EF Core package** ````csharp -var people = _personRepository +var queryable = await _personRepository.GetQueryableAsync(); +var people = queryable .Where(p => p.Name.Contains(nameFilter)) .ToListAsync(); ```` @@ -285,7 +288,8 @@ If you are using [MongoDB](MongoDB.md), you need to add the [Volo.Abp.MongoDB](h **Example: Cast `IQueryable` to `IMongoQueryable` and use `ToListAsync()`** ````csharp -var people = ((IMongoQueryable)_personRepository +var queryable = await _personRepository.GetQueryableAsync(); +var people = ((IMongoQueryable) queryable .Where(p => p.Name.Contains(nameFilter))) .ToListAsync(); ```` @@ -312,10 +316,11 @@ The standard LINQ extension methods are supported: *AllAsync, AnyAsync, AverageA This approach still **has a limitation**. You need to call the extension method directly on the repository object. For example, the below usage is **not supported**: ```csharp -var count = await _bookRepository.Where(x => x.Name.Contains("A")).CountAsync(); +var queryable = await _bookRepository.GetQueryableAsync(); +var count = await queryable.Where(x => x.Name.Contains("A")).CountAsync(); ``` -This is because the object returned from the `Where` method is not a repository object, it is a standard `IQueryable` interface. See the other options for such cases. +This is because the `CountAsync()` method in this example is called on a `IQueryable` interface, not on the repository object. See the other options for such cases. This method is suggested **wherever possible**. @@ -352,8 +357,11 @@ namespace AbpDemo public async Task> GetListAsync(string name) { + //Obtain the IQueryable + var queryable = await _productRepository.GetQueryableAsync(); + //Create the query - var query = _productRepository + var query = queryable .Where(p => p.Name.Contains(name)) .OrderBy(p => p.Name); diff --git a/docs/en/Specifications.md b/docs/en/Specifications.md index 036baa749e..bfe1d031d3 100644 --- a/docs/en/Specifications.md +++ b/docs/en/Specifications.md @@ -122,7 +122,8 @@ namespace MyProject public async Task> GetCustomersCanBuyAlcohol() { - var query = _customerRepository.Where( + var queryable = await _customerRepository.GetQueryableAsync(); + var query = queryable.Where( new Age18PlusCustomerSpecification().ToExpression() ); @@ -137,7 +138,8 @@ namespace MyProject Actually, using the `ToExpression()` method is not necessary since the specifications are automatically casted to Expressions. This would also work: ````csharp -var query = _customerRepository.Where( +var queryable = await _customerRepository.GetQueryableAsync(); +var query = queryable.Where( new Age18PlusCustomerSpecification() ); ````