mirror of https://github.com/abpframework/abp.git
csharpabpc-sharpframeworkblazoraspnet-coredotnet-coreaspnetcorearchitecturesaasdomain-driven-designangularmulti-tenancy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.9 KiB
5.9 KiB
MongoDB Integration
This document offers best practices for implementing MongoDB integration in your modules and applications.
Ensure you've read the MongoDB Integration document first.
General
- Do define a separated
MongoDbContextinterface and class for each module.
MongoDbContext Interface
- Do define an interface for the
MongoDbContextthat inherits fromIAbpMongoDbContext. - Do add a
ConnectionStringNameattribute to theMongoDbContextinterface. - Do add
IMongoCollection<TEntity>properties to theMongoDbContextinterface only for the aggregate roots. Example:
[ConnectionStringName("AbpIdentity")]
public interface IAbpIdentityMongoDbContext : IAbpMongoDbContext
{
IMongoCollection<IdentityUser> Users { get; }
IMongoCollection<IdentityRole> Roles { get; }
}
MongoDbContext class
- Do inherit the
MongoDbContextfrom theAbpMongoDbContextclass. - Do add a
ConnectionStringNameattribute to theMongoDbContextclass. - Do implement the corresponding
interfacefor theMongoDbContextclass. Example:
[ConnectionStringName("AbpIdentity")]
public class AbpIdentityMongoDbContext : AbpMongoDbContext, IAbpIdentityMongoDbContext
{
public IMongoCollection<IdentityUser> Users => Collection<IdentityUser>();
public IMongoCollection<IdentityRole> Roles => Collection<IdentityRole>();
//code omitted for brevity
}
Collection Prefix
- Do add static
CollectionPrefixproperty to theDbContextclass. Set default value from a constant. Example:
public static string CollectionPrefix { get; set; } = AbpIdentityConsts.DefaultDbTablePrefix;
Used the same constant defined for the EF Core integration table prefix in this example.
- Do always use a short
CollectionPrefixvalue for a module to create unique collection names in a shared database.Abpcollection prefix is reserved for ABP core modules.
Collection Mapping
- Do explicitly configure all aggregate roots by overriding the
CreateModelmethod of theMongoDbContext. Example:
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
modelBuilder.ConfigureIdentity();
}
- Do not configure model directly in the
CreateModelmethod. Instead, create an extension method for theIMongoModelBuilder. Use ConfigureModuleName as the method name. Example:
public static class AbpIdentityMongoDbContextExtensions
{
public static void ConfigureIdentity(
this IMongoModelBuilder builder,
Action<IdentityMongoModelBuilderConfigurationOptions> optionsAction = null)
{
Check.NotNull(builder, nameof(builder));
builder.Entity<IdentityUser>(b =>
{
b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "Users";
});
builder.Entity<IdentityRole>(b =>
{
b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "Roles";
});
}
}
Repository Implementation
- Do inherit the repository from the
MongoDbRepository<TMongoDbContext, TEntity, TKey>class and implement the corresponding repository interface. Example:
public class MongoIdentityUserRepository
: MongoDbRepository<IAbpIdentityMongoDbContext, IdentityUser, Guid>,
IIdentityUserRepository
{
public MongoIdentityUserRepository(
IMongoDbContextProvider<IAbpIdentityMongoDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}
- Do pass the
cancellationTokento the MongoDB Driver using theGetCancellationTokenhelper method. Example:
public async Task<IdentityUser> FindByNormalizedUserNameAsync(
string normalizedUserName,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync())
.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 ignore the
includeDetailsparameters for the repository implementation since MongoDB loads the aggregate root as a whole (including sub collections) by default. - Do use the
GetQueryableAsync()method to obtain anIQueryable<TEntity>to perform queries wherever possible. Because;GetQueryableAsync()method automatically uses theApplyDataFiltersmethod to filter the data based on the current data filters (like soft delete and multi-tenancy).- Using
IQueryable<TEntity>makes the code as much as similar to the EF Core repository implementation and easy to write and read.
- Do implement data filtering if it is not possible to use the
GetQueryableAsync()method.
Module Class
- Do define a module class for the MongoDB integration package.
- Do add
MongoDbContextto theIServiceCollectionusing theAddMongoDbContext<TMongoDbContext>method. - Do add implemented repositories to the options for the
AddMongoDbContext<TMongoDbContext>method. Example:
[DependsOn(
typeof(AbpIdentityDomainModule),
typeof(AbpUsersMongoDbModule)
)]
public class AbpIdentityMongoDbModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMongoDbContext<AbpIdentityMongoDbContext>(options =>
{
options.AddRepository<IdentityUser, MongoIdentityUserRepository>();
options.AddRepository<IdentityRole, MongoIdentityRoleRepository>();
});
}
}
Notice that this module class also calls the static BsonClassMap configuration method defined above.