From a861f91c3819bc3d7a05b35db2d85657fc93bae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 21 Jan 2021 17:45:28 +0300 Subject: [PATCH] Update Entity-Framework-Core.md --- docs/en/Entity-Framework-Core.md | 91 +++++++++++++++++--------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md index b2b216397a..d1cc5e1a6f 100644 --- a/docs/en/Entity-Framework-Core.md +++ b/docs/en/Entity-Framework-Core.md @@ -344,7 +344,7 @@ You have different options when you want to load the related entities while quer #### Repository.WithDetails -`IRepository.WithDetails(...)` can be used to include one relation collection/property to the query. +`IRepository.WithDetailsAsync(...)` can be used to get an `IQueryable` by including one relation collection/property. **Example: Get an order with lines** @@ -355,7 +355,7 @@ using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Services; -namespace MyCrm +namespace AbpDemo.Orders { public class OrderManager : DomainService { @@ -368,35 +368,39 @@ namespace MyCrm public async Task TestWithDetails(Guid id) { - var query = _orderRepository - .WithDetails(x => x.Lines) - .Where(x => x.Id == id); - + //Get a IQueryable by including sub collections + var queryable = await _orderRepository.WithDetailsAsync(x => x.Lines); + + //Apply additional LINQ extension methods + var query = queryable.Where(x => x.Id == id); + + //Execute the query and get the result var order = await AsyncExecuter.FirstOrDefaultAsync(query); } } } ```` -> `AsyncExecuter` is used to execute async LINQ extensions without depending on the EF Core. If you add EF Core NuGet package reference to your project, then you can directly use `await _orderRepository.WithDetails(x => x.Lines).FirstOrDefaultAsync()`. But, this time you depend on the EF Core in your domain layer. See the [repository document](Repositories.md) to learn more. +> `AsyncExecuter` is used to execute async LINQ extensions without depending on the EF Core. If you add EF Core NuGet package reference to your project, then you can directly use `await query.FirstOrDefaultAsync()`. But, this time you depend on the EF Core in your domain layer. See the [repository document](Repositories.md) to learn more. **Example: Get a list of orders with their lines** ````csharp public async Task TestWithDetails() { - var query = _orderRepository - .WithDetails(x => x.Lines); + //Get a IQueryable by including sub collections + var queryable = await _orderRepository.WithDetailsAsync(x => x.Lines); - var orders = await AsyncExecuter.ToListAsync(query); + //Execute the query and get the result + var orders = await AsyncExecuter.ToListAsync(queryable); } ```` -> `WithDetails` method can get more than one expression parameter if you need to include more than one navigation property or collection. +> `WithDetailsAsync` method can get more than one expression parameter if you need to include more than one navigation property or collection. #### DefaultWithDetailsFunc -If you don't pass any expression to the `WithDetails` method, then it includes all the details using the `DefaultWithDetailsFunc` option you provide. +If you don't pass any expression to the `WithDetailsAsync` method, then it includes all the details using the `DefaultWithDetailsFunc` option you provide. You can configure `DefaultWithDetailsFunc` for an entity in the `ConfigureServices` method of your [module](Module-Development-Basics.md) in your `EntityFrameworkCore` project. @@ -419,12 +423,15 @@ Then you can use the `WithDetails` without any parameter: ````csharp public async Task TestWithDetails() { - var query = _orderRepository.WithDetails(); - var orders = await AsyncExecuter.ToListAsync(query); + //Get a IQueryable by including all sub collections + var queryable = await _orderRepository.WithDetailsAsync(); + + //Execute the query and get the result + var orders = await AsyncExecuter.ToListAsync(queryable); } ```` -`WithDetails()` executes the expression you've setup as the `DefaultWithDetailsFunc`. +`WithDetailsAsync()` executes the expression you've setup as the `DefaultWithDetailsFunc`. #### Repository Get/Find Methods @@ -466,7 +473,7 @@ public async Task TestWithDetails() #### Alternatives -The repository patters tries to encapsulate the EF Core, so your options are limited. If you need an advanced scenario, you can follow one of the options; +The repository pattern tries to encapsulate the EF Core, so your options are limited. If you need an advanced scenario, you can follow one of the options; * Create a custom repository method and use the complete EF Core API. * Reference to the `Volo.Abp.EntityFrameworkCore` package from your project. In this way, you can directly use `Include` and `ThenInclude` in your code. @@ -550,24 +557,15 @@ See also [lazy loading document](https://docs.microsoft.com/en-us/ef/core/queryi In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository pattern). However, if you want to access the `DbContext` instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example: ````csharp -public class BookService +public async Task TestAsync() { - private readonly IRepository _bookRepository; - - public BookService(IRepository bookRepository) - { - _bookRepository = bookRepository; - } - - public void Foo() - { - DbContext dbContext = _bookRepository.GetDbContext(); - DbSet books = _bookRepository.GetDbSet(); - } + var dbContext = await _orderRepository.GetDbContextAsync(); + var dbSet = await _orderRepository.GetDbSetAsync(); + //var dbSet = dbContext.Set(); //Alternative, when you have the DbContext } ```` -* `GetDbContext` returns a `DbContext` reference instead of `BookStoreDbContext`. You can cast it, however in most cases you don't need it. +* `GetDbContextAsync` returns a `DbContext` reference instead of `BookStoreDbContext`. You can cast it if you need. However, you don't need it in most cases. > Important: You must reference to the `Volo.Abp.EntityFrameworkCore` package from the project you want to access to the `DbContext`. This breaks encapsulation, but this is what you want in that case. @@ -742,32 +740,36 @@ If you have better logic or using an external library for bulk operations, you c - You may use example template below: ```csharp -public class MyCustomEfCoreBulkOperationProvider : IEfCoreBulkOperationProvider, ITransientDependency -{ - public async Task DeleteManyAsync(IEfCoreRepository repository, - IEnumerable entities, - bool autoSave, - CancellationToken cancellationToken) +public class MyCustomEfCoreBulkOperationProvider + : IEfCoreBulkOperationProvider, ITransientDependency +{ + public async Task DeleteManyAsync( + IEfCoreRepository repository, + IEnumerable entities, + bool autoSave, + CancellationToken cancellationToken) where TDbContext : IEfCoreDbContext where TEntity : class, IEntity { // Your logic here. } - public async Task InsertManyAsync(IEfCoreRepository repository, - IEnumerable entities, - bool autoSave, - CancellationToken cancellationToken) + public async Task InsertManyAsync( + IEfCoreRepository repository, + IEnumerable entities, + bool autoSave, + CancellationToken cancellationToken) where TDbContext : IEfCoreDbContext where TEntity : class, IEntity { // Your logic here. } - public async Task UpdateManyAsync(IEfCoreRepository repository, - IEnumerable entities, - bool autoSave, - CancellationToken cancellationToken) + public async Task UpdateManyAsync( + IEfCoreRepository repository, + IEnumerable entities, + bool autoSave, + CancellationToken cancellationToken) where TDbContext : IEfCoreDbContext where TEntity : class, IEntity { @@ -779,3 +781,4 @@ public class MyCustomEfCoreBulkOperationProvider : IEfCoreBulkOperationProvider, ## See Also * [Entities](Entities.md) +* [Repositories](Repositories.md)