mirror of https://github.com/abpframework/abp
				
				
				
			
			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.
		
		
		
		
		
			
		
			
				
					
					
						
							202 lines
						
					
					
						
							6.8 KiB
						
					
					
				
			
		
		
	
	
							202 lines
						
					
					
						
							6.8 KiB
						
					
					
				| ## MongoDB 集成
 | |
| 
 | |
| * **推荐** 为每个模块定义一个独立的 `MongoDbContext` 接口与实现类.
 | |
| 
 | |
| ### MongoDbContext 接口
 | |
| 
 | |
| - **推荐** 定义 `MongoDbContext` **接口** 时继承自 `IAbpMongoDbContext`.
 | |
| - **推荐** 添加 `ConnectionStringName` **attribute** 到 `MongoDbContext` 接口.
 | |
| - **推荐** 只把聚合根做为 `IMongoCollection<TEntity>` **properties** 添加到 `MongoDbContext` 接口. 示例:
 | |
| 
 | |
| ````C#
 | |
| [ConnectionStringName("AbpIdentity")]
 | |
| public interface IAbpIdentityMongoDbContext : IAbpMongoDbContext
 | |
| {
 | |
|     IMongoCollection<IdentityUser> Users { get; }
 | |
|     IMongoCollection<IdentityRole> Roles { get; }
 | |
| }
 | |
| ````
 | |
| 
 | |
| ### MongoDbContext 类
 | |
| 
 | |
| - **推荐**  `MongoDbContext` 继承自 `AbpMongoDbContext` 类.
 | |
| - **推荐** 添加 `ConnectionStringName` **attribute** 到 `MongoDbContext` 类.
 | |
| - **推荐** `MongoDbContext` 类实现相对应的**接口**.  示例:
 | |
| 
 | |
| ```c#
 | |
| [ConnectionStringName("AbpIdentity")]
 | |
| public class AbpIdentityMongoDbContext : AbpMongoDbContext, IAbpIdentityMongoDbContext
 | |
| {
 | |
|     public IMongoCollection<IdentityUser> Users => Collection<IdentityUser>();
 | |
|     public IMongoCollection<IdentityRole> Roles => Collection<IdentityRole>();
 | |
| 
 | |
|     //code omitted for brevity
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Collection 前缀
 | |
| 
 | |
| - **推荐** 添加静态 `CollectionPrefix` **property** 到 `DbContext` 类中并使用常量为其设置默认值. 示例:
 | |
| 
 | |
| ```c#
 | |
| public static string CollectionPrefix { get; set; } = AbpIdentityConsts.DefaultDbTablePrefix;
 | |
| ```
 | |
| 
 | |
| 在此示例中使用与EF Core集成表前缀相同的常量.
 | |
| 
 | |
| - **推荐** 总是使用简短的 `CollectionPrefix` 值为模块在共享数据库中创建  **unique collection names**. `Abp` collection前缀是为ABP Core模块保留的.
 | |
| 
 | |
| ### Collection 映射
 | |
| 
 | |
| - **推荐** 通过重写 `MongoDbContext` 的 `CreateModel` 方法  **配置所有的聚合根** . 示例:
 | |
| 
 | |
| ```c#
 | |
| protected override void CreateModel(IMongoModelBuilder modelBuilder)
 | |
| {
 | |
|     base.CreateModel(modelBuilder);
 | |
| 
 | |
|     modelBuilder.ConfigureIdentity(options =>
 | |
|     {
 | |
|         options.CollectionPrefix = CollectionPrefix;
 | |
|     });
 | |
| }
 | |
| ```
 | |
| 
 | |
| - **不推荐** 直接在 `CreateModel` 方法中配置model,而是为 `IMongoModelBuilder` 定义一个 **扩展方法**. 使用Configure*ModuleName*作为方法名称. 示例:
 | |
| 
 | |
| ```c#
 | |
| public static class AbpIdentityMongoDbContextExtensions
 | |
| {
 | |
|     public static void ConfigureIdentity(
 | |
|         this IMongoModelBuilder builder,
 | |
|         Action<IdentityMongoModelBuilderConfigurationOptions> optionsAction = null)
 | |
|     {
 | |
|         Check.NotNull(builder, nameof(builder));
 | |
| 
 | |
|         var options = new IdentityMongoModelBuilderConfigurationOptions();
 | |
| 
 | |
|         optionsAction?.Invoke(options);
 | |
| 
 | |
|         builder.Entity<IdentityUser>(b =>
 | |
|         {
 | |
|             b.CollectionName = options.CollectionPrefix + "Users";
 | |
|         });
 | |
| 
 | |
|         builder.Entity<IdentityRole>(b =>
 | |
|         {
 | |
|             b.CollectionName = options.CollectionPrefix + "Roles";
 | |
|         });
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| - **推荐** 通过继承 `AbpMongoModelBuilderConfigurationOptions` 来创建 **configuration Options** 类. 示例:
 | |
| 
 | |
| ```c#
 | |
| public class IdentityMongoModelBuilderConfigurationOptions
 | |
|     : AbpMongoModelBuilderConfigurationOptions
 | |
| {
 | |
|     public IdentityMongoModelBuilderConfigurationOptions()
 | |
|         : base(AbpIdentityConsts.DefaultDbTablePrefix)
 | |
|     {
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| * **推荐** 创建一个静态方法, 显示地为所有的实体配置 `BsonClassMap`. 示例:
 | |
| 
 | |
| ````C#
 | |
| public static class AbpIdentityBsonClassMap
 | |
| {
 | |
|     private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
 | |
| 
 | |
|     public static void Configure()
 | |
|     {
 | |
|         OneTimeRunner.Run(() =>
 | |
|         {
 | |
|             BsonClassMap.RegisterClassMap<IdentityUser>(map =>
 | |
|             {
 | |
|                 map.AutoMap();
 | |
|                 map.ConfigureExtraProperties();
 | |
|             });
 | |
| 
 | |
|             BsonClassMap.RegisterClassMap<IdentityRole>(map =>
 | |
|             {
 | |
|                 map.AutoMap();
 | |
|             });
 | |
|         });
 | |
|     }
 | |
| }
 | |
| ````
 | |
| 
 | |
| `BsonClassMap` 适用于静态方法. 所以只需要在应用程序配置一次实体. `OneTimeRunner` 以线程安全的方式运行, 并且在应用程序生命周期中只运行一次. 上面代码中的映射确保单元测试可以正确运行. 此代码将由下面的**模块类**调用.
 | |
| 
 | |
| ### 仓储实现
 | |
| 
 | |
| - **推荐** 仓储 **继承自** `MongoDbRepository<TMongoDbContext, TEntity, TKey>` 类并且实现其相应的接口. 示例:
 | |
| 
 | |
| ```c#
 | |
| public class MongoIdentityUserRepository
 | |
|     : MongoDbRepository<IAbpIdentityMongoDbContext, IdentityUser, Guid>,
 | |
|       IIdentityUserRepository
 | |
| {
 | |
|     public MongoIdentityUserRepository(
 | |
|         IMongoDbContextProvider<IAbpIdentityMongoDbContext> dbContextProvider) 
 | |
|         : base(dbContextProvider)
 | |
|     {
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| - **推荐** 使用 `GetCancellationToken` 帮助方法将 `cancellationToken` 传递给MongoDB驱动程序. 示例:
 | |
| 
 | |
| ```c#
 | |
| public async Task<IdentityUser> FindByNormalizedUserNameAsync(
 | |
|     string normalizedUserName, 
 | |
|     bool includeDetails = true,
 | |
|     CancellationToken cancellationToken = default)
 | |
| {
 | |
|     return await GetMongoQueryable()
 | |
|         .FirstOrDefaultAsync(
 | |
|             u => u.NormalizedUserName == normalizedUserName,
 | |
|             GetCancellationToken(cancellationToken)
 | |
|         );
 | |
| }
 | |
| ```
 | |
| 
 | |
| 如果调用者代码中未提供取消令牌, 则 `GetCancellationToken` 会从`ICancellationTokenProvider.Token` 获取取消令牌
 | |
| `GetCancellationToken`.
 | |
| 
 | |
| * **推荐** 忽略仓储实现中的 `includeDetails` 参数, 因为MongoDB在默认情况下将聚合根作为一个整体(包括子集合)加载.
 | |
| * **推荐** 使用 `GetMongoQueryable()` 方法获取 `IQueryable<TEntity>` 以尽可能执行查询use the `GetMongoQueryable()` method to obtain an `IQueryable<TEntity>` to perform queries  wherever possible. 因为;
 | |
|   *  `GetMongoQueryable()` 方法在内部使用 `ApplyDataFilters` 方法根据当前的过滤器 (如 软删除与多租户)过滤数据.
 | |
|   * 使用`IQueryable<TEntity>`让代码与EF Core仓储实现类似, 易于使用.
 | |
| * **推荐** 如果无法使用 `GetMongoQueryable()` 方法, 则应自行实现数据过滤.
 | |
| 
 | |
| ### 模块类
 | |
| 
 | |
| - **推荐** 为MongoDB集成包定义一个模块类.
 | |
| - **推荐** 使用 `AddMongoDbContext<TMongoDbContext>` 方法将 `MongoDbContext` 添加到 `IServiceCollection`.
 | |
| - **推荐** 将已实现的仓储添加到 `AddMongoDbContext<TMongoDbContext>` 方法options中. 示例:
 | |
| 
 | |
| ```c#
 | |
| [DependsOn(
 | |
|     typeof(AbpIdentityDomainModule),
 | |
|     typeof(AbpUsersMongoDbModule)
 | |
|     )]
 | |
| public class AbpIdentityMongoDbModule : AbpModule
 | |
| {
 | |
|     public override void ConfigureServices(ServiceConfigurationContext context)
 | |
|     {
 | |
|         AbpIdentityBsonClassMap.Configure();
 | |
| 
 | |
|         context.Services.AddMongoDbContext<AbpIdentityMongoDbContext>(options =>
 | |
|         {
 | |
|             options.AddRepository<IdentityUser, MongoIdentityUserRepository>();
 | |
|             options.AddRepository<IdentityRole, MongoIdentityRoleRepository>();
 | |
|         });
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| 需要注意的是, 模块类还调用上面定义的静态 `BsonClassMap` 配置方法. |