@ -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<T>` 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<T> 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<T> by including sub collections
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<T> 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:
var dbContext = await _orderRepository.GetDbContextAsync();
var dbSet = await _orderRepository.GetDbSetAsync();
//var dbSet = dbContext.Set<Order>(); //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<TDbContext,TEntity>(IEfCoreRepository<TEntity> repository,