diff --git a/MEVD/src/AzureDocumentDB/AzureDocumentDB.csproj b/MEVD/src/AzureDocumentDB/AzureDocumentDB.csproj index 0fc87c9..d5dc7e5 100644 --- a/MEVD/src/AzureDocumentDB/AzureDocumentDB.csproj +++ b/MEVD/src/AzureDocumentDB/AzureDocumentDB.csproj @@ -1,7 +1,7 @@  - 1.0.1 + 1.0.2 CommunityToolkit.VectorData.AzureDocumentDB $(AssemblyName) net10.0;net8.0;netstandard2.1;net472 diff --git a/MEVD/src/AzureDocumentDB/MongoShared/MongoMapper.cs b/MEVD/src/AzureDocumentDB/MongoShared/MongoMapper.cs index 1afe8bf..f417de6 100644 --- a/MEVD/src/AzureDocumentDB/MongoShared/MongoMapper.cs +++ b/MEVD/src/AzureDocumentDB/MongoShared/MongoMapper.cs @@ -27,18 +27,10 @@ internal sealed class MongoMapper : IMongoMapper /// A key property name of the data model. private readonly string _keyPropertyModelName; - /// - /// Initializes a new instance of the class. - /// - /// The model. - public MongoMapper(CollectionModel model) + static MongoMapper() { - this._model = model; - - var keyProperty = model.KeyProperty; - this._keyPropertyModelName = keyProperty.ModelName; - this._keyClrProperty = keyProperty.PropertyInfo; - + // ConventionRegistry is process-wide and every Register call adds a new entry, + // so the conventions are registered once per record type instead of once per instance. var conventionPack = new ConventionPack { new IgnoreExtraElementsConvention(ignoreExtraElements: true), @@ -51,6 +43,19 @@ public MongoMapper(CollectionModel model) type => type == typeof(TRecord)); } + /// + /// Initializes a new instance of the class. + /// + /// The model. + public MongoMapper(CollectionModel model) + { + this._model = model; + + var keyProperty = model.KeyProperty; + this._keyPropertyModelName = keyProperty.ModelName; + this._keyClrProperty = keyProperty.PropertyInfo; + } + public BsonDocument MapFromDataToStorageModel(TRecord dataModel, int recordIndex, IReadOnlyList?[]? generatedEmbeddings) { var document = dataModel.ToBsonDocument(); diff --git a/MEVD/test/AzureDocumentDB.UnitTests/DocumentDBCollectionTests.cs b/MEVD/test/AzureDocumentDB.UnitTests/DocumentDBCollectionTests.cs index 954d11a..3d2f588 100644 --- a/MEVD/test/AzureDocumentDB.UnitTests/DocumentDBCollectionTests.cs +++ b/MEVD/test/AzureDocumentDB.UnitTests/DocumentDBCollectionTests.cs @@ -12,6 +12,7 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Conventions; using MongoDB.Driver; using Moq; using Xunit; @@ -72,6 +73,28 @@ public void ConstructorWithImperativeModelInitializesCollection() Assert.NotNull(collection); } + [Fact] + public void ConstructorRegistersConventionsOncePerRecordType() + { + // Arrange + using var firstCollection = new DocumentDBCollection( + this._mockMongoDatabase.Object, + "collection"); + + var conventionCount = ConventionRegistry.Lookup(typeof(ConventionTestModel)).Conventions.Count(); + + // Act + for (var i = 0; i < 3; i++) + { + using var collection = new DocumentDBCollection( + this._mockMongoDatabase.Object, + "collection"); + } + + // Assert + Assert.Equal(conventionCount, ConventionRegistry.Lookup(typeof(ConventionTestModel)).Conventions.Count()); + } + [Theory] [MemberData(nameof(CollectionExistsData))] public async Task CollectionExistsReturnsValidResultAsync(List collections, string collectionName, bool expectedResult) @@ -708,6 +731,15 @@ private sealed class VectorSearchModel [VectorStoreVector(dimensions: 4, DistanceFunction = DistanceFunction.CosineDistance, IndexKind = IndexKind.IvfFlat)] public ReadOnlyMemory TestEmbedding2 { get; set; } } + + private sealed class ConventionTestModel + { + [VectorStoreKey] + public string? Id { get; set; } + + [VectorStoreData] + public string? HotelName { get; set; } + } #pragma warning restore CA1812 #endregion