集成MongoDB需要用到这个包.将它安装到你的项目中(如果是多层架构,安装到数据层和基础设施层):

    然后添加 AbpMongoDbModule 依赖到你的 中:

    1. using Volo.Abp.MongoDB;
    2. using Volo.Abp.Modularity;
    3. namespace MyCompany.MyProject
    4. {
    5. [DependsOn(typeof(AbpMongoDbModule))]
    6. public class MyModule : AbpModule
    7. {
    8. //...
    9. }
    10. }

    ABP中引入了 Mongo Db Context 的概念(跟Entity Framework Core的DbContext很像)让使用和配置集合变得更简单.举个例子:

    1. public class MyDbContext : AbpMongoDbContext
    2. {
    3. public IMongoCollection<Question> Questions => Collection<Question>();
    4. public IMongoCollection<Category> Categories => Collection<Category>();
    5. protected override void CreateModel(IMongoModelBuilder modelBuilder)
    6. {
    7. modelBuilder.Entity<Question>(b =>
    8. {
    9. b.CollectionName = "Questions";
    10. });
    11. }
    12. }
    • 继承 AbpMongoDbContext
    • 为每一个mongo集合添加一个公共的 IMongoCollection<TEntity> 属性.ABP默认使用这些属性创建默认的仓储
    • 重写 CreateModel 方法,可以在方法中配置集合(如设置集合在数据库中的名字)

    在你的模块中使用 AddAbpDbContext 方法将Db Context注入到依赖注入系统中.

    1. using Microsoft.Extensions.DependencyInjection;
    2. using Volo.Abp.MongoDB;
    3. using Volo.Abp.Modularity;
    4. namespace MyCompany.MyProject
    5. {
    6. [DependsOn(typeof(AbpMongoDbModule))]
    7. public class MyModule : AbpModule
    8. {
    9. public override void ConfigureServices(ServiceConfigurationContext context)
    10. {
    11. context.Services.AddMongoDbContext<MyDbContext>();
    12. }
    13. }
    14. }

    添加默认的仓储

    在注入的时候使用 AddDefaultRepositories(), ABP就能自动为Db Context中的每一个实体创建仓储:

    1. services.AddMongoDbContext<MyDbContext>(options =>
    2. {
    3. options.AddDefaultRepositories();
    4. });

    这样就会默认为每一个聚合根实体(继承自AggregateRoot的类)创建一个仓储.如果你也想为其他的实体创建仓储,将 includeAllEntities 设置为 true就可以了:

    1. services.AddMongoDbContext<MyDbContext>(options =>
    2. {
    3. options.AddDefaultRepositories(includeAllEntities: true);
    4. });

    现在可以在你的服务中注入并使用IRepository<TEntity>IQueryableRepository<TEntity>了.比如你有一个主键类型为Guid的实体:

    1. public class Book : AggregateRoot<Guid>
    2. {
    3. public string Name { get; set; }
    4. public BookType Type { get; set; }
    5. }

    (BookType是个枚举)你想在中创建一个Book实体:

    这是一个使用InsertAsync方法将一个实体插入到数据库的例子.

    添加自定义仓储

    大多数情况下默认的泛型仓储已经足够用了(因为它们实现了IQueryable).然而,你可能需要创建自定义的仓库并添加自己的仓储方法.

    1. public interface IBookRepository : IRepository<Book, Guid>
    2. {
    3. Task DeleteBooksByType(
    4. BookType type,
    5. CancellationToken cancellationToken = default(CancellationToken)
    6. );
    7. }

    通常你希望从IRepository中继承标准的仓储方法.其实,你不必那么做.仓储接口定义在领域层,在数据层/基础设施层实现.(中的MongoDB项目)

    实现IBookRepository接口的例子:

    1. public class BookRepository :
    2. MongoDbRepository<BookStoreMongoDbContext, Book, Guid>,
    3. IBookRepository
    4. {
    5. public BookRepository(IMongoDbContextProvider<BookStoreMongoDbContext> dbContextProvider)
    6. : base(dbContextProvider)
    7. {
    8. }
    9. public async Task DeleteBooksByType(
    10. BookType type,
    11. CancellationToken cancellationToken = default(CancellationToken))
    12. {
    13. await Collection.DeleteManyAsync(
    14. Builders<Book>.Filter.Eq(b => b.Type, type),
    15. cancellationToken
    16. );
    17. }
    18. }

    现在,就能在需要的时候注入IBookRepository并使用DeleteBooksByType方法了.

    重写默认的泛型仓储

    即使你创建了自定义仓储,你仍然可以注入默认的泛型仓储(本例中的IRepository<Book, Guid>).默认的仓储实现不会使用你创建的类.

    如果你想用自定义的仓储替换默认的仓储实现,在AddMongoDbContext中做:

    1. context.Services.AddMongoDbContext<BookStoreMongoDbContext>(options =>
    2. {
    3. options.AddDefaultRepositories();
    4. options.AddRepository<Book, BookRepository>(); //替换 IRepository<Book, Guid>
    5. });

    当你想重写基础仓储方法时,这一点尤为重要.例如,你想要重写DeleteAsync方法,以便更有效的删除实体:

    1. public async override Task DeleteAsync(
    2. Guid id,
    3. bool autoSave = false,
    4. CancellationToken cancellationToken = default)
    5. {
    6. }

    访问MongoDB API

    大多数情况下,你想要将MongoDB API隐藏在仓储后面(这是仓储的主要目的).如果你想在仓储之上访问MongoDB API,你可以使用GetDatabaseAsync(), GetAggregateAsync()GetCollectionAsync()方法.例如:

    1. public class BookService
    2. {
    3. public BookService(IRepository<Book, Guid> bookRepository)
    4. {
    5. _bookRepository = bookRepository;
    6. }
    7. public async Task FooAsync()
    8. {
    9. IMongoDatabase database = await _bookRepository.GetDatabaseAsync();
    10. IMongoCollection<Book> books = await _bookRepository.GetCollectionAsync();
    11. IAggregateFluent<Book> bookAggregate = await _bookRepository.GetAggregateAsync();
    12. }
    13. }

    事务

    MongoDB在4.0版本开始支持事务, ABP在3.2版本加入了对MongoDb事务的支持. 如果你升级到3.2版本,需要将MongoDbSchemaMigrator添加到你的 .MongoDB 项目中.

    默认在 .MongoDB 项目中禁用了工作单元事务. 如果你的MongoDB服务器支持事务,你可以手动启用工作单元的事务:

    1. Configure<AbpUnitOfWorkDefaultOptions>(options =>
    2. {
    3. options.TransactionBehavior = UnitOfWorkTransactionBehavior.Enabled;
    4. });

    高级主题

    设置默认的仓储类

    首先,像下面这样定义你的仓储类:

    第一个是复合主键的实体,第二个是只有一个主键的实体.

    如果需要重写方法建议继承MongoDbRepository类,否则,你需要手动实现所有的仓储方法.

    现在,你可以使用SetDefaultRepositoryClasses:

    1. context.Services.AddMongoDbContext<BookStoreMongoDbContext>(options =>
    2. {
    3. options.SetDefaultRepositoryClasses(
    4. typeof(MyRepositoryBase<,>),
    5. typeof(MyRepositoryBase<>)
    6. );
    7. //...
    8. });
    为默认的仓储设置基类或接口

    如果你的MongoDbContext继承自另一个MongoDbContext或者实现了某个接口,你可以使用这个基类或者接口作为默认仓储的类型.如:

    1. public interface IBookStoreMongoDbContext : IAbpMongoDbContext
    2. {
    3. Collection<Book> Books { get; }
    4. }

    IBookStoreMongoDbContextBookStoreMongoDbContext类实现.然后你就可以在AddDefaultRepositories中使用:

    1. context.Services.AddMongoDbContext<BookStoreMongoDbContext>(options =>
    2. {
    3. options.AddDefaultRepositories<IBookStoreMongoDbContext>();
    4. //...
    5. });

    现在,你自定义的BookRepository类也可以使用IBookStoreMongoDbContext接口:

    1. public class BookRepository
    2. : MongoDbRepository<IBookStoreMongoDbContext, Book, Guid>,
    3. IBookRepository
    4. {
    5. //...
    6. }

    为MongoDbContext使用接口的优点就是它可以被另一个实现替换.

    替换其他的DbContexts

    一旦你正确定义并为MongoDbContext使用了接口,任何其他实现都可以使用以下方法替换它:

    ReplaceDbContextAttribute

    1. [ReplaceDbContext(typeof(IBookStoreMongoDbContext))]
    2. public class OtherMongoDbContext : AbpMongoDbContext, IBookStoreMongoDbContext
    3. {
    4. //...
    5. }
    1. context.Services.AddMongoDbContext<OtherMongoDbContext>(options =>
    2. {
    3. //...
    4. options.ReplaceDbContext<IBookStoreMongoDbContext>();

    这个例子中,实现了IBookStoreMongoDbContext.这个特性允许你在发开的时候使用多个MongoDbContext(每个模块一个),但是运行的时候只能使有一个MongoDbContext(实现所有MongoDbContexts的所有接口)