- **Do not** configure model directly in the `OnModelCreating` method. Instead, create an extension method for `ModelBuilder`. Use Configure*ModuleName* as the method name. Example:
- **Do not** configure model directly in the `OnModelCreating` method. Instead, create an **extension method** for `ModelBuilder`. Use Configure*ModuleName* as the method name. Example:
````C#
public static class IdentityDbContextModelBuilderExtensions
@ -206,7 +206,7 @@ public static class IdentityDbContextModelBuilderExtensions
}
````
* Do create a configuration options class by inheriting from the `ModelBuilderConfigurationOptions`. Example:
* **Do** create a **configuration options** class by inheriting from the `ModelBuilderConfigurationOptions`. Example:
````C#
public class IdentityModelBuilderConfigurationOptions : ModelBuilderConfigurationOptions
@ -219,12 +219,93 @@ public class IdentityModelBuilderConfigurationOptions : ModelBuilderConfiguratio
}
````
###### Repository Implementation
- **Do****inherit** the repository from the `EfCoreRepository<TDbContext, TEntity, TKey>` class and implement the corresponding repository interface. Example:
* **Do** pass the `cancellationToken` to EF Core using the `GetCancellationToken` helper method. Example:
````C#
public virtual async Task<IdentityUser> FindByNormalizedUserNameAsync(
string normalizedUserName,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await DbSet
.IncludeDetails(includeDetails)
.FirstOrDefaultAsync(
u => u.NormalizedUserName == normalizedUserName,
GetCancellationToken(cancellationToken)
);
}
````
`GetCancellationToken` fallbacks to the `ICancellationTokenProvider.Token` to obtain the cancellation token if it is not provided by the caller code.
- **Do** create a `IncludeDetails`**extension method** for the `IQueryable<TEntity>` for each aggregate root which has **sub collections**. Example:
````C#
public static IQueryable<IdentityUser> IncludeDetails(
this IQueryable<IdentityUser> queryable,
bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.Roles)
.Include(x => x.Logins)
.Include(x => x.Claims)
.Include(x => x.Tokens);
}
````
* **Do** use the `IncludeDetails` extension method in the repository methods just like used in the example code above (see FindByNormalizedUserNameAsync).
- **Do** override `IncludeDetails` method of the repository for aggregates root which have **sub collections**. Example: