版本
语言

MongoDB 集成

  • 推荐 为每个模块定义一个独立的 MongoDbContext 接口与实现类.

MongoDbContext 接口

  • 推荐 定义 MongoDbContext 接口 时继承自 IAbpMongoDbContext.
  • 推荐 添加 ConnectionStringName attributeMongoDbContext 接口.
  • 推荐 只把聚合根做为 IMongoCollection<TEntity> properties 添加到 MongoDbContext 接口. 示例:
[ConnectionStringName("AbpIdentity")]
public interface IAbpIdentityMongoDbContext : IAbpMongoDbContext
{
    IMongoCollection<IdentityUser> Users { get; }
    IMongoCollection<IdentityRole> Roles { get; }
}

MongoDbContext 类

  • 推荐 MongoDbContext 继承自 AbpMongoDbContext 类.
  • 推荐 添加 ConnectionStringName attributeMongoDbContext 类.
  • 推荐 MongoDbContext 类实现相对应的接口. 示例:
[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 propertyDbContext 类中并使用常量为其设置默认值. 示例:
public static string CollectionPrefix { get; set; } = AbpIdentityConsts.DefaultDbTablePrefix;

在此示例中使用与EF Core集成表前缀相同的常量.

  • 推荐 总是使用简短的 CollectionPrefix 值为模块在共享数据库中创建 unique collection names. Abp collection前缀是为ABP Core模块保留的.

Collection 映射

  • 推荐 通过重写 MongoDbContextCreateModel 方法 配置所有的聚合根 . 示例:
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
    base.CreateModel(modelBuilder);

    modelBuilder.ConfigureIdentity(options =>
    {
        options.CollectionPrefix = CollectionPrefix;
    });
}
  • 不推荐 直接在 CreateModel 方法中配置model,而是为 IMongoModelBuilder 定义一个 扩展方法. 使用ConfigureModuleName作为方法名称. 示例:
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 类. 示例:
public class IdentityMongoModelBuilderConfigurationOptions
    : AbpMongoModelBuilderConfigurationOptions
{
    public IdentityMongoModelBuilderConfigurationOptions()
        : base(AbpIdentityConsts.DefaultDbTablePrefix)
    {
    }
}
  • 推荐 创建一个静态方法, 显示地为所有的实体配置 BsonClassMap. 示例:
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> 类并且实现其相应的接口. 示例:
public class MongoIdentityUserRepository
    : MongoDbRepository<IAbpIdentityMongoDbContext, IdentityUser, Guid>,
      IIdentityUserRepository
{
    public MongoIdentityUserRepository(
        IMongoDbContextProvider<IAbpIdentityMongoDbContext> dbContextProvider) 
        : base(dbContextProvider)
    {
    }
}
  • 推荐 使用 GetCancellationToken 帮助方法将 cancellationToken 传递给MongoDB驱动程序. 示例:
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中. 示例:
[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 配置方法.

本页对您有帮助吗?
请进行选择。
感谢您的宝贵意见!

请注意,虽然我们无法回复反馈意见,但我们的团队会根据您的意见改进体验。

在本文档中
Mastering ABP Framework Book
掌握 ABP 框架

本书将帮助你全面了解框架和现代Web应用程序开发技术。