diff --git a/docs/en/MongoDB.md b/docs/en/MongoDB.md index 0faa6a7d26..df7f92e779 100644 --- a/docs/en/MongoDB.md +++ b/docs/en/MongoDB.md @@ -82,6 +82,34 @@ If you only need to configure the collection name, you can also use `[MongoColle public IMongoCollection Questions => Collection(); ```` +### Configure Indexes and CreateCollectionOptions for a Collection + +You can configure indexes and `CreateCollectionOptions` for your collections by overriding the `CreateModel` method. Example: + +````csharp +protected override void CreateModel(IMongoModelBuilder modelBuilder) +{ + base.CreateModel(modelBuilder); + + modelBuilder.Entity(b => + { + b.CreateCollectionOptions.Collation = new Collation(locale:"en_US", strength: CollationStrength.Secondary); + b.ConfigureIndexes(indexes => + { + indexes.CreateOne( + new CreateIndexModel( + Builders.IndexKeys.Ascending("MyProperty"), + new CreateIndexOptions { Unique = true } + ) + ); + } + ); + }); +} +```` + +This example sets a collation for the collection and creates a unique index for the `MyProperty` property. + ### Configure the Connection String Selection If you have multiple databases in your application, you can configure the connection string name for your DbContext using the `[ConnectionStringName]` attribute. Example: diff --git a/docs/zh-Hans/MongoDB.md b/docs/zh-Hans/MongoDB.md index 540793dd1f..1602c61a38 100644 --- a/docs/zh-Hans/MongoDB.md +++ b/docs/zh-Hans/MongoDB.md @@ -51,6 +51,34 @@ public class MyDbContext : AbpMongoDbContext * 为每一个mongo集合添加一个公共的 `IMongoCollection` 属性.ABP默认使用这些属性创建默认的仓储 * 重写 `CreateModel` 方法,可以在方法中配置集合(如设置集合在数据库中的名字) +### 为集合配置索引和 CreateCollectionOptions + +你可以在 `CreateModel` 方法中配置集合的索引和 `CreateCollectionOptions`: + +````csharp +protected override void CreateModel(IMongoModelBuilder modelBuilder) +{ + base.CreateModel(modelBuilder); + + modelBuilder.Entity(b => + { + b.CreateCollectionOptions.Collation = new Collation(locale:"en_US", strength: CollationStrength.Secondary); + b.ConfigureIndexes(indexes => + { + indexes.CreateOne( + new CreateIndexModel( + Builders.IndexKeys.Ascending("MyProperty"), + new CreateIndexOptions { Unique = true } + ) + ); + } + ); + }); +} +```` + +在这个例子中,我们设置了集合的排序规则和一个唯一的索引. + ### 将 Db Context 注入到依赖注入中 在你的模块中使用 `AddAbpDbContext` 方法将Db Context注入到[依赖注入](Dependency-Injection.md)系统中. diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IHasCreateCollectionOptions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IHasCreateCollectionOptions.cs new file mode 100644 index 0000000000..c9340bddca --- /dev/null +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IHasCreateCollectionOptions.cs @@ -0,0 +1,9 @@ +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Volo.Abp.MongoDB; + +public interface IHasCreateCollectionOptions +{ + CreateCollectionOptions CreateCollectionOptions { get; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IHasMongoIndexManagerAction.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IHasMongoIndexManagerAction.cs new file mode 100644 index 0000000000..54c2970b93 --- /dev/null +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IHasMongoIndexManagerAction.cs @@ -0,0 +1,10 @@ +using System; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Volo.Abp.MongoDB; + +public interface IHasMongoIndexManagerAction +{ + Action>? IndexesAction { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoEntityModelBuilder.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoEntityModelBuilder.cs index 673f1f4288..fd781aac20 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoEntityModelBuilder.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoEntityModelBuilder.cs @@ -1,5 +1,7 @@ using System; +using MongoDB.Bson; using MongoDB.Bson.Serialization; +using MongoDB.Driver; namespace Volo.Abp.MongoDB; @@ -10,6 +12,10 @@ public interface IMongoEntityModelBuilder string CollectionName { get; set; } BsonClassMap BsonMap { get; } + + CreateCollectionOptions CreateCollectionOptions { get; } + + void ConfigureIndexes(Action> action); } public interface IMongoEntityModelBuilder @@ -19,4 +25,8 @@ public interface IMongoEntityModelBuilder string CollectionName { get; set; } BsonClassMap BsonMap { get; } + + CreateCollectionOptions CreateCollectionOptions { get; } + + void ConfigureIndexes(Action> action); } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs index e012e89072..14f46e1df7 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs @@ -1,19 +1,28 @@ using MongoDB.Bson.Serialization; using System; +using MongoDB.Bson; +using MongoDB.Driver; namespace Volo.Abp.MongoDB; public class MongoEntityModelBuilder : IMongoEntityModel, IHasBsonClassMap, + IHasCreateCollectionOptions, + IHasMongoIndexManagerAction, IMongoEntityModelBuilder, IMongoEntityModelBuilder { public Type EntityType { get; } public string CollectionName { get; set; } = default!; + + public Action>? IndexesAction { get; set; } + + public CreateCollectionOptions CreateCollectionOptions { get; } BsonClassMap IMongoEntityModelBuilder.BsonMap => _bsonClassMap; + BsonClassMap IMongoEntityModelBuilder.BsonMap => _bsonClassMap; private readonly BsonClassMap _bsonClassMap; @@ -23,10 +32,16 @@ public class MongoEntityModelBuilder : EntityType = typeof(TEntity); _bsonClassMap = new BsonClassMap(); _bsonClassMap.ConfigureAbpConventions(); + CreateCollectionOptions = new CreateCollectionOptions(); } public BsonClassMap GetMap() { return _bsonClassMap; } + + public void ConfigureIndexes(Action>? indexesAction) + { + IndexesAction = indexesAction; + } } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs index b7de3043ac..d7ad79f7d0 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs @@ -74,7 +74,10 @@ public class MongoModelBuilder : IMongoModelBuilder baseClasses.AddRange(entityModel.EntityType.GetBaseClasses(includeObject: false)); - CreateCollectionIfNotExists(dbContext, entityModel.CollectionName); + var createCollectionOptions = entityModel.As().CreateCollectionOptions; + var indexesAction = entityModel.As().IndexesAction; + CreateCollectionIfNotExists(dbContext, entityModel.CollectionName, createCollectionOptions); + CreateCollectionIndexes(dbContext, entityModel.CollectionName, indexesAction); } baseClasses = baseClasses.Distinct().ToList(); @@ -141,7 +144,7 @@ public class MongoModelBuilder : IMongoModelBuilder typeof(MongoEntityModelBuilder<>).MakeGenericType(entityType) )! ); - + buildAction?.Invoke(model); } @@ -150,14 +153,24 @@ public class MongoModelBuilder : IMongoModelBuilder return _entityModelBuilders.Values.Cast().ToImmutableList(); } - protected virtual void CreateCollectionIfNotExists(AbpMongoDbContext dbContext, string collectionName) + protected virtual void CreateCollectionIfNotExists(AbpMongoDbContext dbContext, string collectionName, CreateCollectionOptions createCollectionOptions) { var filter = new BsonDocument("name", collectionName); - var options = new ListCollectionNamesOptions { Filter = filter }; + var options = new ListCollectionsOptions { Filter = filter }; + + if (!dbContext.Database.ListCollections(options).Any()) + { + dbContext.Database.CreateCollection(collectionName, createCollectionOptions); + } + } - if (!dbContext.Database.ListCollectionNames(options).Any()) + protected virtual void CreateCollectionIndexes(AbpMongoDbContext dbContext, string collectionName, Action>? indexesAction = null) + { + var collection = dbContext.Database.GetCollection(collectionName); + + if (collection != null) { - dbContext.Database.CreateCollection(collectionName); + indexesAction?.Invoke(collection.Indexes); } } } diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs index 7c4bd0441d..0d5122228d 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Driver.Linq; using Shouldly; +using Volo.Abp.Domain.Repositories; using Volo.Abp.TestApp; using Volo.Abp.TestApp.Domain; using Volo.Abp.TestApp.Testing; @@ -64,4 +65,16 @@ public class Repository_Basic_Tests : Repository_Basic_Tests p.PersonId == person.Id && p.Number == "1234567890").ShouldBeTrue(); } + + [Fact] + public async Task Filter_Case_Insensitive() + { + (await CityRepository.GetMongoQueryableAsync()).FirstOrDefault(c => c.Name == "ISTANBUL").ShouldBeNull(); + (await CityRepository.GetMongoQueryableAsync()).FirstOrDefault(c => c.Name == "istanbul").ShouldBeNull(); + (await CityRepository.GetMongoQueryableAsync()).FirstOrDefault(c => c.Name == "Istanbul").ShouldNotBeNull(); + + (await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "douglas").ShouldNotBeNull(); + (await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "DOUGLAS").ShouldNotBeNull(); + (await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "Douglas").ShouldNotBeNull(); + } } diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs index 9bc2606878..fc1ef00cd4 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs @@ -1,4 +1,5 @@ -using MongoDB.Driver; +using MongoDB.Bson; +using MongoDB.Driver; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext; @@ -35,5 +36,10 @@ public class TestAppMongoDbContext : AbpMongoDbContext, ITestAppMongoDbContext, { b.CollectionName = "MyCities"; }); + + modelBuilder.Entity(b => + { + b.CreateCollectionOptions.Collation = new Collation(locale:"en_US", strength: CollationStrength.Secondary); + }); } }