From 283e99c7ef2f82df20346cc98c642aa3540ae6f4 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Tue, 27 Dec 2022 22:26:38 +1030 Subject: [PATCH 01/10] Move core types into single file --- .../Mapping/EntityDefinition.cs | 78 +++++++++++++++++-- .../Infrastructure/Mapping/EntityIndex.cs | 14 ---- .../Infrastructure/Mapping/EntityProperty.cs | 25 ------ .../Mapping/IEntityDefinition.cs | 14 ---- .../Infrastructure/Mapping/IEntityIndex.cs | 14 ---- .../Infrastructure/Mapping/IEntityProperty.cs | 18 ----- 6 files changed, 71 insertions(+), 92 deletions(-) delete mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs index 5c979cd5..eb1e66f3 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs @@ -1,15 +1,79 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; -namespace MongoFramework.Infrastructure.Mapping +namespace MongoFramework.Infrastructure.Mapping; + +public interface IEntityDefinition +{ + Type EntityType { get; set; } + string CollectionName { get; set; } + IEntityKeyGenerator KeyGenerator { get; set; } + IEnumerable Properties { get; set; } + IEnumerable Indexes { get; set; } +} + +public interface IEntityProperty +{ + Type EntityType { get; } + bool IsKey { get; } + string ElementName { get; } + string FullPath { get; } + Type PropertyType { get; } + PropertyInfo PropertyInfo { get; } + + object GetValue(object entity); + void SetValue(object entity, object value); +} + +public interface IEntityIndex +{ + IEntityProperty Property { get; } + string IndexName { get; } + bool IsUnique { get; } + IndexSortOrder SortOrder { get; } + int IndexPriority { get; } + IndexType IndexType { get; } + bool IsTenantExclusive { get; set; } +} + +public class EntityDefinition : IEntityDefinition { - public class EntityDefinition : IEntityDefinition + public Type EntityType { get; set; } + public string CollectionName { get; set; } + public IEntityKeyGenerator KeyGenerator { get; set; } + public IEnumerable Properties { get; set; } = Enumerable.Empty(); + public IEnumerable Indexes { get; set; } = Enumerable.Empty(); +} + +public class EntityProperty : IEntityProperty +{ + public Type EntityType { get; set; } + public bool IsKey { get; set; } + public string ElementName { get; set; } + public string FullPath { get; set; } + public Type PropertyType { get; set; } + public PropertyInfo PropertyInfo { get; set; } + + public object GetValue(object entity) { - public Type EntityType { get; set; } - public string CollectionName { get; set; } - public IEntityKeyGenerator KeyGenerator { get; set; } - public IEnumerable Properties { get; set; } = Enumerable.Empty(); - public IEnumerable Indexes { get; set; } = Enumerable.Empty(); + return PropertyInfo.GetValue(entity); + } + + public void SetValue(object entity, object value) + { + PropertyInfo.SetValue(entity, value); } } + +public class EntityIndex : IEntityIndex +{ + public IEntityProperty Property { get; set; } + public string IndexName { get; set; } + public bool IsUnique { get; set; } + public IndexSortOrder SortOrder { get; set; } + public int IndexPriority { get; set; } + public IndexType IndexType { get; set; } + public bool IsTenantExclusive { get; set; } +} \ No newline at end of file diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs b/src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs deleted file mode 100644 index b3bea7dd..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs +++ /dev/null @@ -1,14 +0,0 @@ - -namespace MongoFramework.Infrastructure.Mapping -{ - public class EntityIndex : IEntityIndex - { - public IEntityProperty Property { get; set; } - public string IndexName { get; set; } - public bool IsUnique { get; set; } - public IndexSortOrder SortOrder { get; set; } - public int IndexPriority { get; set; } - public IndexType IndexType { get; set; } - public bool IsTenantExclusive { get; set; } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs b/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs deleted file mode 100644 index cb52bbcb..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Reflection; - -namespace MongoFramework.Infrastructure.Mapping -{ - public class EntityProperty : IEntityProperty - { - public Type EntityType { get; set; } - public bool IsKey { get; set; } - public string ElementName { get; set; } - public string FullPath { get; set; } - public Type PropertyType { get; set; } - public PropertyInfo PropertyInfo { get; set; } - - public object GetValue(object entity) - { - return PropertyInfo.GetValue(entity); - } - - public void SetValue(object entity, object value) - { - PropertyInfo.SetValue(entity, value); - } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs deleted file mode 100644 index 0cb6347d..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MongoFramework.Infrastructure.Mapping -{ - public interface IEntityDefinition - { - Type EntityType { get; set; } - string CollectionName { get; set; } - IEntityKeyGenerator KeyGenerator { get; set; } - IEnumerable Properties { get; set; } - IEnumerable Indexes { get; set; } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs deleted file mode 100644 index e8834bf9..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs +++ /dev/null @@ -1,14 +0,0 @@ - -namespace MongoFramework.Infrastructure.Mapping -{ - public interface IEntityIndex - { - IEntityProperty Property { get; } - string IndexName { get; } - bool IsUnique { get; } - IndexSortOrder SortOrder { get; } - int IndexPriority { get; } - IndexType IndexType { get; } - bool IsTenantExclusive { get; set; } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs deleted file mode 100644 index 8c6bfecd..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Reflection; - -namespace MongoFramework.Infrastructure.Mapping -{ - public interface IEntityProperty - { - Type EntityType { get; } - bool IsKey { get; } - string ElementName { get; } - string FullPath { get; } - Type PropertyType { get; } - PropertyInfo PropertyInfo { get; } - - object GetValue(object entity); - void SetValue(object entity, object value); - } -} From 9f7ee4a25096747cb1d596200914e87bfd929721 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 00:18:35 +1030 Subject: [PATCH 02/10] First pass to split mapping construction --- .../Commands/AddToBucketCommand.cs | 6 +- .../Indexing/IndexModelBuilder.cs | 2 +- .../Mapping/DriverMappingInterop.cs | 58 ++++++++++++ .../Mapping/EntityDefinition.cs | 91 +++++++++++++------ .../Mapping/EntityDefinitionExtensions.cs | 14 +-- .../Mapping/EntityKeyGenerator.cs | 54 ++++++++--- .../Infrastructure/Mapping/EntityMapping.cs | 11 +-- .../Mapping/IEntityKeyGenerator.cs | 7 -- .../Mapping/Processors/EntityIdProcessor.cs | 27 +++--- .../Processors/ExtraElementsProcessor.cs | 20 ++-- .../Mapping/Processors/IndexProcessor.cs | 4 +- .../Processors/PropertyMappingProcessor.cs | 14 ++- src/MongoFramework/IsExternalInit.cs | 13 +++ src/MongoFramework/Linq/LinqExtensions.cs | 2 +- src/MongoFramework/MongoDbBucketSet.cs | 2 +- .../MappingAdapterProcessorTests.cs | 2 +- 16 files changed, 226 insertions(+), 101 deletions(-) create mode 100644 src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityKeyGenerator.cs create mode 100644 src/MongoFramework/IsExternalInit.cs diff --git a/src/MongoFramework/Infrastructure/Commands/AddToBucketCommand.cs b/src/MongoFramework/Infrastructure/Commands/AddToBucketCommand.cs index cbfebab3..192c34b3 100644 --- a/src/MongoFramework/Infrastructure/Commands/AddToBucketCommand.cs +++ b/src/MongoFramework/Infrastructure/Commands/AddToBucketCommand.cs @@ -11,12 +11,12 @@ public class AddToBucketCommand : IWriteCommand typeof(EntityBucket); - public AddToBucketCommand(TGroup group, TSubEntity subEntity, IEntityProperty entityTimeProperty, int bucketSize) + public AddToBucketCommand(TGroup group, TSubEntity subEntity, IEntityPropertyDefinition entityTimeProperty, int bucketSize) { Group = group; SubEntity = subEntity; @@ -42,7 +42,7 @@ public IEnumerable>> GetModel(WriteM .Min(b => b.Min, itemTimeValue) .Max(b => b.Max, itemTimeValue) .SetOnInsert(b => b.BucketSize, BucketSize) - .SetOnInsert(b => b.Id, entityDefinition.KeyGenerator.Generate()); + .SetOnInsert(b => b.Id, entityDefinition.Key.KeyGenerator.Generate()); yield return new UpdateOneModel>(filter, updateDefinition) { diff --git a/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs b/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs index b8c59752..5267fe44 100644 --- a/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs +++ b/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs @@ -43,7 +43,7 @@ public static IEnumerable> BuildModel() } } - private static CreateIndexModel CreateIndexModel(IEntityIndex indexDefinition) + private static CreateIndexModel CreateIndexModel(IEntityIndexDefinition indexDefinition) { var builder = Builders.IndexKeys; IndexKeysDefinition keyModel; diff --git a/src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs b/src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs new file mode 100644 index 00000000..d2328de6 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs @@ -0,0 +1,58 @@ +using MongoDB.Bson.Serialization; + +namespace MongoFramework.Infrastructure.Mapping; + +/// +/// Maps the MongoFramework definition into something the MongoDB Driver will understand +/// +internal static class DriverMappingInterop +{ + /// + /// Registers the as a with all appropriate properties configured. + /// + /// + public static void RegisterDefinition(IEntityDefinition definition) + { + var classMap = new BsonClassMap(definition.EntityType); + + // Hierarchy + if (!EntityMapping.IsValidTypeToMap(definition.EntityType.BaseType)) + { + classMap.SetIsRootClass(true); + } + + // Properties + foreach (var property in definition.Properties) + { + var memberMap = classMap.MapMember(property.PropertyInfo); + memberMap.SetElementName(property.ElementName); + } + + // Key / ID + var idMemberMap = classMap.MapIdMember(definition.Key.Property.PropertyInfo); + idMemberMap.SetIdGenerator(new DriverKeyGeneratorWrapper(definition.Key.KeyGenerator)); + + // Extra Elements + if (definition.ExtraElements.IgnoreExtraElements) + { + classMap.SetIgnoreExtraElements(true); + classMap.SetIgnoreExtraElementsIsInherited(definition.ExtraElements.IgnoreInherited); + } + else + { + classMap.SetIgnoreExtraElements(false); + + var extraElementsProperty = definition.ExtraElements.Property; + foreach (var memberMap in classMap.DeclaredMemberMaps) + { + if (memberMap.ElementName == extraElementsProperty.ElementName) + { + classMap.SetExtraElementsMember(memberMap); + break; + } + } + } + + BsonClassMap.RegisterClassMap(classMap); + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs index eb1e66f3..b5a64134 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs @@ -7,47 +7,68 @@ namespace MongoFramework.Infrastructure.Mapping; public interface IEntityDefinition { - Type EntityType { get; set; } - string CollectionName { get; set; } - IEntityKeyGenerator KeyGenerator { get; set; } - IEnumerable Properties { get; set; } - IEnumerable Indexes { get; set; } + public Type EntityType { get; set; } + public string CollectionName { get; set; } + public IEntityKeyDefinition Key { get; set; } + public IEnumerable Properties { get; set; } + public IEnumerable Indexes { get; set; } + public IEntityExtraElementsDefinition ExtraElements { get; set; } } -public interface IEntityProperty +public interface IEntityPropertyDefinition { - Type EntityType { get; } - bool IsKey { get; } - string ElementName { get; } - string FullPath { get; } - Type PropertyType { get; } - PropertyInfo PropertyInfo { get; } + [Obsolete("Replace with IEntityDefinition _if_ actually needed")] + public Type EntityType { get; } + [Obsolete("Key is defined on IEntityDefinition")] + public bool IsKey { get; } + public string ElementName { get; } + [Obsolete("This should be on a custom EntityProperty type (WalkedEntityProperty)?")] + public string FullPath { get; } + [Obsolete("This is accessible from PropertyInfo")] + public Type PropertyType { get; } + public PropertyInfo PropertyInfo { get; } + + public object GetValue(object entity); + public void SetValue(object entity, object value); +} + +public interface IEntityIndexDefinition +{ + public IReadOnlyCollection Properties { get; } + [Obsolete("Index definition can point to multiple properties directly")] + public IEntityPropertyDefinition Property { get; } + public string IndexName { get; } + public bool IsUnique { get; } + public IndexSortOrder SortOrder { get; } + public int IndexPriority { get; } + public IndexType IndexType { get; } + public bool IsTenantExclusive { get; } +} - object GetValue(object entity); - void SetValue(object entity, object value); +public interface IEntityExtraElementsDefinition +{ + public IEntityPropertyDefinition Property { get; } + public bool IgnoreExtraElements { get; } + public bool IgnoreInherited { get; } } -public interface IEntityIndex +public interface IEntityKeyDefinition { - IEntityProperty Property { get; } - string IndexName { get; } - bool IsUnique { get; } - IndexSortOrder SortOrder { get; } - int IndexPriority { get; } - IndexType IndexType { get; } - bool IsTenantExclusive { get; set; } + public IEntityPropertyDefinition Property { get; } + public IEntityKeyGenerator KeyGenerator { get; } } public class EntityDefinition : IEntityDefinition { public Type EntityType { get; set; } public string CollectionName { get; set; } - public IEntityKeyGenerator KeyGenerator { get; set; } - public IEnumerable Properties { get; set; } = Enumerable.Empty(); - public IEnumerable Indexes { get; set; } = Enumerable.Empty(); + public IEntityKeyDefinition Key { get; set; } + public IEnumerable Properties { get; set; } = Enumerable.Empty(); + public IEnumerable Indexes { get; set; } = Enumerable.Empty(); + public IEntityExtraElementsDefinition ExtraElements { get; set; } } -public class EntityProperty : IEntityProperty +public class EntityPropertyDefinition : IEntityPropertyDefinition { public Type EntityType { get; set; } public bool IsKey { get; set; } @@ -67,13 +88,27 @@ public void SetValue(object entity, object value) } } -public class EntityIndex : IEntityIndex +public class EntityIndexDefinition : IEntityIndexDefinition { - public IEntityProperty Property { get; set; } + public IReadOnlyCollection Properties { get; set; } + public IEntityPropertyDefinition Property { get; set; } public string IndexName { get; set; } public bool IsUnique { get; set; } public IndexSortOrder SortOrder { get; set; } public int IndexPriority { get; set; } public IndexType IndexType { get; set; } public bool IsTenantExclusive { get; set; } +} + +public sealed record EntityKeyDefinition : IEntityKeyDefinition +{ + public IEntityPropertyDefinition Property { get; init; } + public IEntityKeyGenerator KeyGenerator { get; init; } +} + +public sealed record EntityExtraElementsDefinition : IEntityExtraElementsDefinition +{ + public IEntityPropertyDefinition Property { get; init; } + public bool IgnoreExtraElements { get; init; } + public bool IgnoreInherited { get; init; } } \ No newline at end of file diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs index 3bb0b60c..4dee9b16 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs @@ -7,7 +7,7 @@ namespace MongoFramework.Infrastructure.Mapping { public static class EntityDefinitionExtensions { - public static IEntityProperty GetIdProperty(this IEntityDefinition definition) + public static IEntityPropertyDefinition GetIdProperty(this IEntityDefinition definition) { return definition.GetAllProperties().FirstOrDefault(m => m.IsKey); } @@ -32,7 +32,7 @@ public static object GetDefaultId(this IEntityDefinition definition) return null; } - public static IEnumerable GetInheritedProperties(this IEntityDefinition definition) + public static IEnumerable GetInheritedProperties(this IEntityDefinition definition) { var currentType = definition.EntityType.BaseType; while (currentType != typeof(object) && currentType != null) @@ -47,7 +47,7 @@ public static IEnumerable GetInheritedProperties(this IEntityDe } } - public static IEnumerable GetAllProperties(this IEntityDefinition definition) + public static IEnumerable GetAllProperties(this IEntityDefinition definition) { foreach (var property in definition.Properties) { @@ -60,7 +60,7 @@ public static IEnumerable GetAllProperties(this IEntityDefiniti } } - public static IEntityProperty GetProperty(this IEntityDefinition definition, string name) + public static IEntityPropertyDefinition GetProperty(this IEntityDefinition definition, string name) { foreach (var property in definition.GetAllProperties()) { @@ -76,10 +76,10 @@ public static IEntityProperty GetProperty(this IEntityDefinition definition, str private sealed class TraversalState { public HashSet SeenTypes { get; set; } - public IEnumerable Properties { get; set; } + public IEnumerable Properties { get; set; } } - public static IEnumerable TraverseProperties(this IEntityDefinition definition) + public static IEnumerable TraverseProperties(this IEntityDefinition definition) { var stack = new Stack(); stack.Push(new TraversalState @@ -102,7 +102,7 @@ public static IEnumerable TraverseProperties(this IEntityDefini { var nestedProperties = EntityMapping.GetOrCreateDefinition(propertyType) .GetAllProperties() - .Select(p => new EntityProperty + .Select(p => new EntityPropertyDefinition { EntityType = p.EntityType, IsKey = p.IsKey, diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs b/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs index f54bef45..f97741cf 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs @@ -1,19 +1,51 @@ using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.IdGenerators; -namespace MongoFramework.Infrastructure.Mapping +namespace MongoFramework.Infrastructure.Mapping; + +public interface IEntityKeyGenerator +{ + public object Generate(); + public bool IsEmpty(object id); +} + +public class EntityKeyGenerators +{ + public static readonly IEntityKeyGenerator StringKeyGenerator = new EntityKeyGenerator(StringObjectIdGenerator.Instance); + public static readonly IEntityKeyGenerator GuidKeyGenerator = new EntityKeyGenerator(CombGuidGenerator.Instance); + public static readonly IEntityKeyGenerator ObjectIdKeyGenerator = new EntityKeyGenerator(ObjectIdGenerator.Instance); +} + +internal class EntityKeyGenerator : IEntityKeyGenerator { - internal class EntityKeyGenerator : IEntityKeyGenerator + internal IIdGenerator IdGenerator { get; } + + public EntityKeyGenerator(IIdGenerator idGenerator) + { + IdGenerator = idGenerator; + } + + public object Generate() { - private IIdGenerator IdGenerator { get; } + return IdGenerator.GenerateId(null, null); + } + + public bool IsEmpty(object id) + { + return IdGenerator.IsEmpty(id); + } +} - public EntityKeyGenerator(IIdGenerator idGenerator) - { - IdGenerator = idGenerator; - } +internal class DriverKeyGeneratorWrapper : IIdGenerator +{ + private readonly IEntityKeyGenerator entityKeyGenerator; - public object Generate() - { - return IdGenerator.GenerateId(null, null); - } + public DriverKeyGeneratorWrapper(IEntityKeyGenerator entityKeyGenerator) + { + this.entityKeyGenerator = entityKeyGenerator; } + + public object GenerateId(object container, object document) => entityKeyGenerator.Generate(); + + public bool IsEmpty(object id) => entityKeyGenerator.IsEmpty(id); } diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs index b1017bda..93c00e1a 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs @@ -92,21 +92,19 @@ public static IEntityDefinition RegisterType(Type entityType) //We will treat success of this check as if we have registered it just now return definition; } - - var classMap = new BsonClassMap(entityType); definition = new EntityDefinition { EntityType = entityType }; EntityDefinitions.TryAdd(entityType, definition); - BsonClassMap.RegisterClassMap(classMap); foreach (var processor in MappingProcessors) { - processor.ApplyMapping(definition, classMap); + processor.ApplyMapping(definition, null); } + DriverMappingInterop.RegisterDefinition(definition); return definition; } finally @@ -165,20 +163,19 @@ public static bool TryRegisterType(Type entityType, out IEntityDefinition defini return true; } - var classMap = new BsonClassMap(entityType); definition = new EntityDefinition { EntityType = entityType }; EntityDefinitions.TryAdd(entityType, definition); - BsonClassMap.RegisterClassMap(classMap); foreach (var processor in MappingProcessors) { - processor.ApplyMapping(definition, classMap); + processor.ApplyMapping(definition, null); } + DriverMappingInterop.RegisterDefinition(definition); return true; } finally diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityKeyGenerator.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityKeyGenerator.cs deleted file mode 100644 index ee712aac..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityKeyGenerator.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace MongoFramework.Infrastructure.Mapping -{ - public interface IEntityKeyGenerator - { - object Generate(); - } -} \ No newline at end of file diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs index 5c04a52b..cfded198 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs @@ -3,7 +3,6 @@ using System.Reflection; using MongoDB.Bson; using MongoDB.Bson.Serialization; -using MongoDB.Bson.Serialization.IdGenerators; namespace MongoFramework.Infrastructure.Mapping.Processors { @@ -11,7 +10,8 @@ public class EntityIdProcessor : IMappingProcessor { public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { - IEntityProperty idProperty = default; + var keyDefinition = definition.Key; + var idProperty = keyDefinition?.Property; foreach (var property in definition.Properties) { if (property.PropertyInfo.GetCustomAttribute() != null) @@ -28,29 +28,30 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) } } - if (idProperty is EntityProperty entityProperty) + if (idProperty is EntityPropertyDefinition entityProperty) { - classMap.MapIdMember(idProperty.PropertyInfo); - entityProperty.IsKey = true; + var keyGenerator = keyDefinition?.KeyGenerator; //Set an Id Generator based on the member type - var idMemberMap = classMap.IdMemberMap; - var memberType = BsonClassMap.GetMemberInfoType(idMemberMap.MemberInfo); + var memberType = entityProperty.PropertyInfo.PropertyType; if (memberType == typeof(string)) { - idMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance); - definition.KeyGenerator = new EntityKeyGenerator(StringObjectIdGenerator.Instance); + keyGenerator = EntityKeyGenerators.StringKeyGenerator; } else if (memberType == typeof(Guid)) { - idMemberMap.SetIdGenerator(CombGuidGenerator.Instance); - definition.KeyGenerator = new EntityKeyGenerator(CombGuidGenerator.Instance); + keyGenerator = EntityKeyGenerators.GuidKeyGenerator; } else if (memberType == typeof(ObjectId)) { - idMemberMap.SetIdGenerator(ObjectIdGenerator.Instance); - definition.KeyGenerator = new EntityKeyGenerator(ObjectIdGenerator.Instance); + keyGenerator = EntityKeyGenerators.ObjectIdKeyGenerator; } + + definition.Key = new EntityKeyDefinition + { + Property = entityProperty, + KeyGenerator = keyGenerator + }; } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs index 3a0eb886..08c9a449 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs @@ -15,13 +15,14 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) var ignoreExtraElements = entityType.GetCustomAttribute(); if (ignoreExtraElements != null) { - classMap.SetIgnoreExtraElements(true); - classMap.SetIgnoreExtraElementsIsInherited(ignoreExtraElements.IgnoreInherited); + definition.ExtraElements = new EntityExtraElementsDefinition + { + IgnoreExtraElements = true, + IgnoreInherited = ignoreExtraElements.IgnoreInherited + }; } else { - classMap.SetIgnoreExtraElements(false); - //If any of the Entity's properties have the "ExtraElementsAttribute", assign that against the BsonClassMap foreach (var property in definition.Properties) @@ -29,14 +30,11 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) var extraElementsAttribute = property.PropertyInfo.GetCustomAttribute(); if (extraElementsAttribute != null && typeof(IDictionary).IsAssignableFrom(property.PropertyType)) { - foreach (var memberMap in classMap.DeclaredMemberMaps) + definition.ExtraElements = new EntityExtraElementsDefinition { - if (memberMap.ElementName == property.ElementName) - { - classMap.SetExtraElementsMember(memberMap); - return; - } - } + Property = property, + IgnoreExtraElements = false + }; } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs index ca86bb1e..74ae29c3 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs @@ -9,12 +9,12 @@ public class IndexProcessor : IMappingProcessor { public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { - var definitionIndexes = new List(); + var definitionIndexes = new List(); foreach (var property in definition.TraverseProperties()) { foreach (var indexAttribute in property.PropertyInfo.GetCustomAttributes()) { - definitionIndexes.Add(new EntityIndex + definitionIndexes.Add(new EntityIndexDefinition { Property = property, IndexName = indexAttribute.Name, diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs index ee4efbad..e7a1dfc6 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs @@ -12,7 +12,7 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) var entityType = definition.EntityType; var properties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - var definitionProperties = new List(); + var definitionProperties = new List(); foreach (var property in properties) { @@ -41,22 +41,20 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) continue; } - //Do the mapping - var memberMap = classMap.MapMember(property); + var elementName = property.Name; //Set custom element name with the "ColumnAttribute" var columnAttribute = property.GetCustomAttribute(); if (columnAttribute != null) { - var mappedName = columnAttribute.Name; - memberMap.SetElementName(mappedName); + elementName = columnAttribute.Name; } - definitionProperties.Add(new EntityProperty + definitionProperties.Add(new EntityPropertyDefinition { EntityType = definition.EntityType, - ElementName = memberMap.ElementName, - FullPath = memberMap.ElementName, + ElementName = elementName, + FullPath = elementName, PropertyType = property.PropertyType, PropertyInfo = property }); diff --git a/src/MongoFramework/IsExternalInit.cs b/src/MongoFramework/IsExternalInit.cs new file mode 100644 index 00000000..17a51c23 --- /dev/null +++ b/src/MongoFramework/IsExternalInit.cs @@ -0,0 +1,13 @@ +using System.ComponentModel; + +namespace System.Runtime.CompilerServices +{ + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit + { + } +} \ No newline at end of file diff --git a/src/MongoFramework/Linq/LinqExtensions.cs b/src/MongoFramework/Linq/LinqExtensions.cs index 2fedd40e..686f760d 100644 --- a/src/MongoFramework/Linq/LinqExtensions.cs +++ b/src/MongoFramework/Linq/LinqExtensions.cs @@ -35,7 +35,7 @@ public static IQueryable WhereIdMatches(this IQueryable WherePropertyMatches(this IQueryable queryable, IEntityProperty property, IEnumerable values) where TEntity : class + public static IQueryable WherePropertyMatches(this IQueryable queryable, IEntityPropertyDefinition property, IEnumerable values) where TEntity : class { //The cast allows for handling identifiers generically as "IEnumerable". Without the Cast call, we can't handle ObjectId etc. var castMethod = typeof(Enumerable).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static); diff --git a/src/MongoFramework/MongoDbBucketSet.cs b/src/MongoFramework/MongoDbBucketSet.cs index 26a2859c..410e8252 100644 --- a/src/MongoFramework/MongoDbBucketSet.cs +++ b/src/MongoFramework/MongoDbBucketSet.cs @@ -19,7 +19,7 @@ public class MongoDbBucketSet : IMongoDbBucketSet Date: Wed, 28 Dec 2022 00:21:46 +1030 Subject: [PATCH 03/10] Updated processor signature with change --- src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs | 4 ++-- .../Infrastructure/Mapping/IMappingProcessor.cs | 2 +- .../Mapping/Processors/BsonKnownTypesProcessor.cs | 2 +- .../Mapping/Processors/CollectionNameProcessor.cs | 2 +- .../Mapping/Processors/DecimalSerializationProcessor.cs | 2 +- .../Infrastructure/Mapping/Processors/EntityIdProcessor.cs | 2 +- .../Mapping/Processors/ExtraElementsProcessor.cs | 2 +- .../Infrastructure/Mapping/Processors/HierarchyProcessor.cs | 6 +----- .../Infrastructure/Mapping/Processors/IndexProcessor.cs | 2 +- .../Mapping/Processors/MappingAdapterProcessor.cs | 4 ++-- .../Mapping/Processors/NestedTypeProcessor.cs | 2 +- .../Mapping/Processors/PropertyMappingProcessor.cs | 2 +- .../Mapping/Processors/TypeDiscoveryProcessor.cs | 2 +- .../Mapping/Processors/MappingAdapterProcessorTests.cs | 4 ++-- 14 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs index 93c00e1a..5a3c9245 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs @@ -101,7 +101,7 @@ public static IEntityDefinition RegisterType(Type entityType) foreach (var processor in MappingProcessors) { - processor.ApplyMapping(definition, null); + processor.ApplyMapping(definition); } DriverMappingInterop.RegisterDefinition(definition); @@ -172,7 +172,7 @@ public static bool TryRegisterType(Type entityType, out IEntityDefinition defini foreach (var processor in MappingProcessors) { - processor.ApplyMapping(definition, null); + processor.ApplyMapping(definition); } DriverMappingInterop.RegisterDefinition(definition); diff --git a/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs index 4d8b48df..d7aab265 100644 --- a/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs @@ -4,6 +4,6 @@ namespace MongoFramework.Infrastructure.Mapping { public interface IMappingProcessor { - void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap); + void ApplyMapping(IEntityDefinition definition); } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs index da2d40fe..bd0940e8 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs @@ -6,7 +6,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class BsonKnownTypesProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var entityType = definition.EntityType; var bsonKnownTypesAttribute = entityType.GetCustomAttribute(); diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs index ad4b210d..5af71ea6 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs @@ -6,7 +6,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class CollectionNameProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var entityType = definition.EntityType; var collectionName = entityType.Name; diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs index 7b6149ae..d3778f0b 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs @@ -8,7 +8,7 @@ public class DecimalSerializationProcessor : IMappingProcessor { private bool SerializerAdded { get; set; } - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { if (!SerializerAdded) { diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs index cfded198..db0d334d 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs @@ -8,7 +8,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class EntityIdProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var keyDefinition = definition.Key; var idProperty = keyDefinition?.Property; diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs index 08c9a449..f8d66091 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs @@ -7,7 +7,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class ExtraElementsProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var entityType = definition.EntityType; diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs index c7d0b8f5..18b50632 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs @@ -4,17 +4,13 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class HierarchyProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var entityType = definition.EntityType; if (EntityMapping.IsValidTypeToMap(entityType.BaseType)) { EntityMapping.TryRegisterType(entityType.BaseType, out _); } - else - { - classMap.SetIsRootClass(true); - } } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs index 74ae29c3..779f0300 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs @@ -7,7 +7,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class IndexProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var definitionIndexes = new List(); foreach (var property in definition.TraverseProperties()) diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/MappingAdapterProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/MappingAdapterProcessor.cs index ef5f40be..b28718e5 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/MappingAdapterProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/MappingAdapterProcessor.cs @@ -7,7 +7,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class MappingAdapterProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var adapterAttribute = definition.EntityType.GetCustomAttribute(); @@ -20,7 +20,7 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) if (instance != null) { - instance.ApplyMapping(definition, classMap); + instance.ApplyMapping(definition); } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs index eb49a868..f8637334 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs @@ -5,7 +5,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class NestedTypeProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var entityType = definition.EntityType; var properties = definition.Properties; diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs index e7a1dfc6..27ac3cf0 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs @@ -7,7 +7,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class PropertyMappingProcessor : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { var entityType = definition.EntityType; var properties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs index 0175ba53..50d42bd7 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs @@ -7,7 +7,7 @@ public class TypeDiscoveryProcessor : IMappingProcessor { private bool ProviderAdded { get; set; } - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { if (!ProviderAdded) { diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappingAdapterProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappingAdapterProcessorTests.cs index 04102f67..ce3601e3 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappingAdapterProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappingAdapterProcessorTests.cs @@ -15,7 +15,7 @@ public class MappingAdapterProcessorTests : MappingTestBase public class AdapterTestModelMappingAdapter : IMappingProcessor { - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { definition.CollectionName = "Custom"; @@ -59,7 +59,7 @@ public AdapterTestModelMappingAdapterConstructor(string test) } - public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + public void ApplyMapping(IEntityDefinition definition) { throw new NotImplementedException(); } From 3ce85d486994af372d58e4367f4f6dbecd3ba705 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 01:13:17 +1030 Subject: [PATCH 04/10] Fix bugs and update relevant tests --- .../Mapping/DriverMappingInterop.cs | 36 +++++++++++-------- .../Mapping/EntityDefinitionExtensions.cs | 17 +++++---- .../Mapping/EntityKeyGenerator.cs | 8 ++--- .../Processors/ExtraElementsProcessor.cs | 5 +-- src/MongoFramework/Linq/LinqExtensions.cs | 10 ++---- .../Mapping/EntityDefinitionExtensionTests.cs | 2 -- .../Processors/EntityIdProcessorTests.cs | 21 ++++------- .../Processors/ExtraElementsProcessorTests.cs | 1 + 8 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs b/src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs index d2328de6..d24dc063 100644 --- a/src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs +++ b/src/MongoFramework/Infrastructure/Mapping/DriverMappingInterop.cs @@ -29,26 +29,32 @@ public static void RegisterDefinition(IEntityDefinition definition) } // Key / ID - var idMemberMap = classMap.MapIdMember(definition.Key.Property.PropertyInfo); - idMemberMap.SetIdGenerator(new DriverKeyGeneratorWrapper(definition.Key.KeyGenerator)); - - // Extra Elements - if (definition.ExtraElements.IgnoreExtraElements) + if (definition.Key is not null) { - classMap.SetIgnoreExtraElements(true); - classMap.SetIgnoreExtraElementsIsInherited(definition.ExtraElements.IgnoreInherited); + var idMemberMap = classMap.MapIdMember(definition.Key.Property.PropertyInfo); + idMemberMap.SetIdGenerator(new DriverKeyGeneratorWrapper(definition.Key.KeyGenerator)); } - else - { - classMap.SetIgnoreExtraElements(false); - var extraElementsProperty = definition.ExtraElements.Property; - foreach (var memberMap in classMap.DeclaredMemberMaps) + // Extra Elements + if (definition.ExtraElements is not null) + { + if (definition.ExtraElements.IgnoreExtraElements) + { + classMap.SetIgnoreExtraElements(true); + classMap.SetIgnoreExtraElementsIsInherited(definition.ExtraElements.IgnoreInherited); + } + else { - if (memberMap.ElementName == extraElementsProperty.ElementName) + classMap.SetIgnoreExtraElements(false); + + var extraElementsProperty = definition.ExtraElements.Property; + foreach (var memberMap in classMap.DeclaredMemberMaps) { - classMap.SetExtraElementsMember(memberMap); - break; + if (memberMap.ElementName == extraElementsProperty.ElementName) + { + classMap.SetExtraElementsMember(memberMap); + break; + } } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs index 4dee9b16..fb12f504 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs @@ -9,7 +9,12 @@ public static class EntityDefinitionExtensions { public static IEntityPropertyDefinition GetIdProperty(this IEntityDefinition definition) { - return definition.GetAllProperties().FirstOrDefault(m => m.IsKey); + if (definition.Key is null) + { + return EntityMapping.GetOrCreateDefinition(definition.EntityType.BaseType).GetIdProperty(); + } + + return definition.Key?.Property; } public static string GetIdName(this IEntityDefinition definition) @@ -24,7 +29,7 @@ public static object GetIdValue(this IEntityDefinition definition, object entity public static object GetDefaultId(this IEntityDefinition definition) { - var idPropertyType = definition.GetIdProperty()?.PropertyType; + var idPropertyType = definition.GetIdProperty()?.PropertyInfo.PropertyType; if (idPropertyType is { IsValueType: true }) { return Activator.CreateInstance(idPropertyType); @@ -95,7 +100,7 @@ public static IEnumerable TraverseProperties(this IEn { yield return property; - var propertyType = property.PropertyType; + var propertyType = property.PropertyInfo.PropertyType; propertyType = propertyType.GetEnumerableItemTypeOrDefault(); if (EntityMapping.IsValidTypeToMap(propertyType) && !state.SeenTypes.Contains(propertyType)) @@ -104,11 +109,11 @@ public static IEnumerable TraverseProperties(this IEn .GetAllProperties() .Select(p => new EntityPropertyDefinition { - EntityType = p.EntityType, - IsKey = p.IsKey, + //EntityType = p.EntityType, + //IsKey = p.IsKey, ElementName = p.ElementName, FullPath = $"{property.FullPath}.{p.ElementName}", - PropertyType = p.PropertyType, + //PropertyType = p.PropertyType, PropertyInfo = p.PropertyInfo }); diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs b/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs index f97741cf..da1a256b 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs @@ -18,21 +18,21 @@ public class EntityKeyGenerators internal class EntityKeyGenerator : IEntityKeyGenerator { - internal IIdGenerator IdGenerator { get; } + private readonly IIdGenerator idGenerator; public EntityKeyGenerator(IIdGenerator idGenerator) { - IdGenerator = idGenerator; + this.idGenerator = idGenerator; } public object Generate() { - return IdGenerator.GenerateId(null, null); + return idGenerator.GenerateId(null, null); } public bool IsEmpty(object id) { - return IdGenerator.IsEmpty(id); + return idGenerator.IsEmpty(id); } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs index f8d66091..61120651 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs @@ -23,8 +23,7 @@ public void ApplyMapping(IEntityDefinition definition) } else { - //If any of the Entity's properties have the "ExtraElementsAttribute", assign that against the BsonClassMap - + //If any of the Entity's properties have the "ExtraElementsAttribute", use that foreach (var property in definition.Properties) { var extraElementsAttribute = property.PropertyInfo.GetCustomAttribute(); @@ -35,8 +34,10 @@ public void ApplyMapping(IEntityDefinition definition) Property = property, IgnoreExtraElements = false }; + break; } } + } } } diff --git a/src/MongoFramework/Linq/LinqExtensions.cs b/src/MongoFramework/Linq/LinqExtensions.cs index 686f760d..3f5b5d77 100644 --- a/src/MongoFramework/Linq/LinqExtensions.cs +++ b/src/MongoFramework/Linq/LinqExtensions.cs @@ -27,11 +27,7 @@ public static string ToQuery(this IQueryable queryable) public static IQueryable WhereIdMatches(this IQueryable queryable, IEnumerable entityIds) where TEntity : class { - var idProperty = EntityMapping.GetOrCreateDefinition(typeof(TEntity)) - .GetAllProperties() - .Where(p => p.IsKey) - .FirstOrDefault(); - + var idProperty = EntityMapping.GetOrCreateDefinition(typeof(TEntity)).Key.Property; return queryable.WherePropertyMatches(idProperty, entityIds); } @@ -39,14 +35,14 @@ public static IQueryable WherePropertyMatches(this IQueryable< { //The cast allows for handling identifiers generically as "IEnumerable". Without the Cast call, we can't handle ObjectId etc. var castMethod = typeof(Enumerable).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static); - var castedIdentifiers = castMethod.MakeGenericMethod(property.PropertyType).Invoke(null, new[] { values }); + var castedIdentifiers = castMethod.MakeGenericMethod(property.PropertyInfo.PropertyType).Invoke(null, new[] { values }); //Dynamically build the LINQ query, it looks something like: e => castedIdentifiers.Contains(e.{propertyName}) var entityParameter = Expression.Parameter(typeof(TEntity), "e"); var propertyExpression = Expression.Property(entityParameter, property.PropertyInfo.Name); var identifiersExpression = Expression.Constant(castedIdentifiers); var expression = Expression.Lambda>( - Expression.Call(typeof(Enumerable), "Contains", new[] { property.PropertyType }, identifiersExpression, propertyExpression), + Expression.Call(typeof(Enumerable), "Contains", new[] { property.PropertyInfo.PropertyType }, identifiersExpression, propertyExpression), entityParameter ); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs index 82bedb9f..4490c58e 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs @@ -82,8 +82,6 @@ public void TraverseMapping() var result = definition.TraverseProperties().ToArray(); Assert.AreEqual(32, result.Length); - Assert.IsTrue(result.Any(m => m.EntityType == typeof(NestedTraverseMappingModel))); - Assert.IsTrue(result.Any(m => m.EntityType == typeof(InnerNestedTraverseMappingModel))); Assert.IsTrue(result.Any(m => m.FullPath == "RecursionType")); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs index fe7de834..e2496291 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs @@ -58,12 +58,9 @@ public void StringIdGeneratorOnStringProperty() { EntityMapping.AddMappingProcessor(new PropertyMappingProcessor()); EntityMapping.AddMappingProcessor(new EntityIdProcessor()); - EntityMapping.RegisterType(typeof(StringIdGeneratorTestModel)); + var definition = EntityMapping.RegisterType(typeof(StringIdGeneratorTestModel)); - var classMap = BsonClassMap.GetRegisteredClassMaps() - .Where(cm => cm.ClassType == typeof(StringIdGeneratorTestModel)).FirstOrDefault(); - - Assert.AreEqual(typeof(StringObjectIdGenerator), classMap.IdMemberMap.IdGenerator?.GetType()); + Assert.AreEqual(EntityKeyGenerators.StringKeyGenerator, definition.Key.KeyGenerator); } [TestMethod] @@ -71,12 +68,9 @@ public void GuidIdGeneratorOnGuidProperty() { EntityMapping.AddMappingProcessor(new PropertyMappingProcessor()); EntityMapping.AddMappingProcessor(new EntityIdProcessor()); - EntityMapping.RegisterType(typeof(GuidIdGeneratorTestModel)); - - var classMap = BsonClassMap.GetRegisteredClassMaps() - .Where(cm => cm.ClassType == typeof(GuidIdGeneratorTestModel)).FirstOrDefault(); + var definition = EntityMapping.RegisterType(typeof(GuidIdGeneratorTestModel)); - Assert.AreEqual(typeof(CombGuidGenerator), classMap.IdMemberMap.IdGenerator?.GetType()); + Assert.AreEqual(EntityKeyGenerators.GuidKeyGenerator, definition.Key.KeyGenerator); } [TestMethod] @@ -84,12 +78,9 @@ public void ObjectIdGeneratorOnObjectIdProperty() { EntityMapping.AddMappingProcessor(new PropertyMappingProcessor()); EntityMapping.AddMappingProcessor(new EntityIdProcessor()); - EntityMapping.RegisterType(typeof(ObjectIdGeneratorTestModel)); - - var classMap = BsonClassMap.GetRegisteredClassMaps() - .Where(cm => cm.ClassType == typeof(ObjectIdGeneratorTestModel)).FirstOrDefault(); + var definition = EntityMapping.RegisterType(typeof(ObjectIdGeneratorTestModel)); - Assert.AreEqual(typeof(ObjectIdGenerator), classMap.IdMemberMap.IdGenerator?.GetType()); + Assert.AreEqual(EntityKeyGenerators.ObjectIdKeyGenerator, definition.Key.KeyGenerator); } [TestMethod] diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs index c5bfd18f..15857388 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs @@ -38,6 +38,7 @@ public class IgnoreExtraElementsModel [TestMethod] public void ObeysIgnoreExtraElementsAttribute() { + EntityMapping.AddMappingProcessor(new PropertyMappingProcessor()); EntityMapping.AddMappingProcessor(new ExtraElementsProcessor()); EntityMapping.RegisterType(typeof(IgnoreExtraElementsModel)); From 6c2f174b73b68171bc597ee25fa481cf9d589639 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 17:36:42 +1030 Subject: [PATCH 05/10] Allow other types of generic "enumerables" --- .../Infrastructure/Internal/TypeExtensions.cs | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/MongoFramework/Infrastructure/Internal/TypeExtensions.cs b/src/MongoFramework/Infrastructure/Internal/TypeExtensions.cs index d2f38cfc..901ad720 100644 --- a/src/MongoFramework/Infrastructure/Internal/TypeExtensions.cs +++ b/src/MongoFramework/Infrastructure/Internal/TypeExtensions.cs @@ -1,35 +1,45 @@ using System; using System.Collections.Generic; -using System.Linq; -namespace MongoFramework.Infrastructure.Internal +namespace MongoFramework.Infrastructure.Internal; + +internal static class TypeExtensions { - internal static class TypeExtensions + private static readonly HashSet CommonGenericEnumerables = new() + { + typeof(IEnumerable<>), + typeof(IList<>), + typeof(ICollection<>), + typeof(IReadOnlyList<>), + typeof(IReadOnlyCollection<>) + }; + + public static Type GetEnumerableItemTypeOrDefault(this Type type) { - public static Type GetEnumerableItemTypeOrDefault(this Type type) + if (type.IsArray) + { + return type.GetElementType(); + } + else if (type.IsGenericType) { - if (type.IsArray) + if (CommonGenericEnumerables.Contains(type.GetGenericTypeDefinition())) { - return type.GetElementType(); + return type.GetGenericArguments()[0]; } - else if (type.IsGenericType) + else { - if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + //Unlike when the type is directly a known generic enumerable interface, if we start making assumptions + //like that on the interfaces of the type, we can hit edge cases where a type implements multiple interfaces. + foreach (var interfaceType in type.GetInterfaces()) { - return type.GetGenericArguments()[0]; - } - else - { - var compatibleInterfaces = type.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)); - var targetInterface = compatibleInterfaces.FirstOrDefault(); - if (targetInterface != null) + if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { return type.GetGenericArguments()[0]; } } } - - return type; } + + return type; } } From cf0f4f8d52c7ff8d97221f65f787a99d3529983c Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 17:38:10 +1030 Subject: [PATCH 06/10] Improve property traversal and index paths --- .../Indexing/IndexModelBuilder.cs | 6 +- .../Mapping/EntityDefinition.cs | 3 + .../Mapping/EntityDefinitionExtensions.cs | 53 --------- .../Mapping/Processors/IndexProcessor.cs | 6 +- .../Mapping/PropertyTraversalExtensions.cs | 107 ++++++++++++++++++ .../Mapping/EntityDefinitionExtensionTests.cs | 60 ---------- .../PropertyTraversalExtensionTests.cs | 70 ++++++++++++ 7 files changed, 186 insertions(+), 119 deletions(-) create mode 100644 src/MongoFramework/Infrastructure/Mapping/PropertyTraversalExtensions.cs create mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/PropertyTraversalExtensionTests.cs diff --git a/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs b/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs index 5267fe44..421ef488 100644 --- a/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs +++ b/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs @@ -50,16 +50,16 @@ private static CreateIndexModel CreateIndexModel(IEntityIndexDefinition if (indexDefinition.IndexType == IndexType.Text) { - keyModel = builder.Text(indexDefinition.Property.FullPath); + keyModel = builder.Text(indexDefinition.Path); } else if (indexDefinition.IndexType == IndexType.Geo2dSphere) { - keyModel = builder.Geo2DSphere(indexDefinition.Property.FullPath); + keyModel = builder.Geo2DSphere(indexDefinition.Path); } else { keyModel = indexDefinition.SortOrder == IndexSortOrder.Ascending ? - builder.Ascending(indexDefinition.Property.FullPath) : builder.Descending(indexDefinition.Property.FullPath); + builder.Ascending(indexDefinition.Path) : builder.Descending(indexDefinition.Path); } if (indexDefinition.IsTenantExclusive && typeof(IHaveTenantId).IsAssignableFrom(typeof(TEntity))) diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs index b5a64134..49578697 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs @@ -37,6 +37,8 @@ public interface IEntityIndexDefinition public IReadOnlyCollection Properties { get; } [Obsolete("Index definition can point to multiple properties directly")] public IEntityPropertyDefinition Property { get; } + //TODO: This will be made redundant when the broader change to support fluent comes in + public string Path { get; } public string IndexName { get; } public bool IsUnique { get; } public IndexSortOrder SortOrder { get; } @@ -92,6 +94,7 @@ public class EntityIndexDefinition : IEntityIndexDefinition { public IReadOnlyCollection Properties { get; set; } public IEntityPropertyDefinition Property { get; set; } + public string Path { get; set; } public string IndexName { get; set; } public bool IsUnique { get; set; } public IndexSortOrder SortOrder { get; set; } diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs index fb12f504..dc285ce4 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using MongoFramework.Infrastructure.Internal; namespace MongoFramework.Infrastructure.Mapping { @@ -77,57 +76,5 @@ public static IEntityPropertyDefinition GetProperty(this IEntityDefinition defin return default; } - - private sealed class TraversalState - { - public HashSet SeenTypes { get; set; } - public IEnumerable Properties { get; set; } - } - - public static IEnumerable TraverseProperties(this IEntityDefinition definition) - { - var stack = new Stack(); - stack.Push(new TraversalState - { - SeenTypes = new HashSet { definition.EntityType }, - Properties = definition.GetAllProperties() - }); - - while (stack.Count > 0) - { - var state = stack.Pop(); - foreach (var property in state.Properties) - { - yield return property; - - var propertyType = property.PropertyInfo.PropertyType; - propertyType = propertyType.GetEnumerableItemTypeOrDefault(); - - if (EntityMapping.IsValidTypeToMap(propertyType) && !state.SeenTypes.Contains(propertyType)) - { - var nestedProperties = EntityMapping.GetOrCreateDefinition(propertyType) - .GetAllProperties() - .Select(p => new EntityPropertyDefinition - { - //EntityType = p.EntityType, - //IsKey = p.IsKey, - ElementName = p.ElementName, - FullPath = $"{property.FullPath}.{p.ElementName}", - //PropertyType = p.PropertyType, - PropertyInfo = p.PropertyInfo - }); - - stack.Push(new TraversalState - { - SeenTypes = new HashSet(state.SeenTypes) - { - propertyType - }, - Properties = nestedProperties - }); - } - } - } - } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs index 779f0300..c1f25b61 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Reflection; -using MongoDB.Bson.Serialization; using MongoFramework.Attributes; namespace MongoFramework.Infrastructure.Mapping.Processors @@ -12,11 +11,12 @@ public void ApplyMapping(IEntityDefinition definition) var definitionIndexes = new List(); foreach (var property in definition.TraverseProperties()) { - foreach (var indexAttribute in property.PropertyInfo.GetCustomAttributes()) + foreach (var indexAttribute in property.Property.PropertyInfo.GetCustomAttributes()) { definitionIndexes.Add(new EntityIndexDefinition { - Property = property, + Property = property.Property, + Path = property.GetPath(), IndexName = indexAttribute.Name, IsUnique = indexAttribute.IsUnique, SortOrder = indexAttribute.SortOrder, diff --git a/src/MongoFramework/Infrastructure/Mapping/PropertyTraversalExtensions.cs b/src/MongoFramework/Infrastructure/Mapping/PropertyTraversalExtensions.cs new file mode 100644 index 00000000..26a9cce6 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/PropertyTraversalExtensions.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System; +using MongoFramework.Infrastructure.Internal; +using System.Linq; +using System.Buffers; +using System.Diagnostics; + +namespace MongoFramework.Infrastructure.Mapping; + +public interface ITraversedProperty +{ + public ITraversedProperty Parent { get; } + public IEntityPropertyDefinition Property { get; } + public int Depth { get; } + public string GetPath(); +} + +[DebuggerDisplay("Property = {Property.ElementName}, Parent = {Parent?.Property?.ElementName}, Depth = {Depth}")] +internal record TraversedProperty : ITraversedProperty +{ + private static readonly string ElementSeparator = "."; + + public ITraversedProperty Parent { get; init; } + public IEntityPropertyDefinition Property { get; init; } + public int Depth { get; init; } + + public string GetPath() + { + if (Depth == 0) + { + return Property.ElementName; + } + + var pool = ArrayPool.Shared.Rent(Depth + 1); + try + { + ITraversedProperty current = this; + for (var i = Depth; i >= 0; i--) + { + pool[i] = current.Property.ElementName; + current = current.Parent; + } + + return string.Join(ElementSeparator, pool, 0, Depth + 1); + } + finally + { + ArrayPool.Shared.Return(pool); + } + } +} + +public static class PropertyTraversalExtensions +{ + private readonly record struct TraversalState + { + public HashSet SeenTypes { get; init; } + public IEnumerable Properties { get; init; } + } + + public static IEnumerable TraverseProperties(this IEntityDefinition definition) + { + var stack = new Stack(); + stack.Push(new TraversalState + { + SeenTypes = new HashSet { definition.EntityType }, + Properties = definition.GetAllProperties().Select(p => new TraversedProperty + { + Property = p, + Depth = 0 + }) + }); + + while (stack.Count > 0) + { + var state = stack.Pop(); + foreach (var traversedProperty in state.Properties) + { + yield return traversedProperty; + + var propertyType = traversedProperty.Property.PropertyInfo.PropertyType; + propertyType = propertyType.GetEnumerableItemTypeOrDefault(); + + if (EntityMapping.IsValidTypeToMap(propertyType) && !state.SeenTypes.Contains(propertyType)) + { + var nestedProperties = EntityMapping.GetOrCreateDefinition(propertyType) + .GetAllProperties() + .Select(p => new TraversedProperty + { + Parent = traversedProperty, + Property = p, + Depth = traversedProperty.Depth + 1 + }); + + stack.Push(new TraversalState + { + SeenTypes = new HashSet(state.SeenTypes) + { + propertyType + }, + Properties = nestedProperties + }); + } + } + } + } +} \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs index 4490c58e..d3a04982 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs @@ -20,30 +20,6 @@ public class IdNameChildModel : IdNameParentModel public string Description { get; set; } } - public class TraverseMappingModel - { - public string Id { get; set; } - public NestedTraverseMappingModel NestedModel { get; set; } - public NestedTraverseMappingModel RepeatedType { get; set; } - public TraverseMappingModel RecursionType { get; set; } - - public NestedTraverseMappingModel[] ArrayModel { get; set; } - public IEnumerable EnumerableModel { get; set; } - public List ListModel { get; set; } - - } - public class NestedTraverseMappingModel - { - public string PropertyOne { get; set; } - public int PropertyTwo { get; set; } - public InnerNestedTraverseMappingModel InnerModel { get; set; } - } - public class InnerNestedTraverseMappingModel - { - public string InnerMostProperty { get; set; } - public TraverseMappingModel NestedRecursionType { get; set; } - } - public class OverridePropertyBaseModel { public virtual string TargetProperty { get; set; } @@ -75,42 +51,6 @@ public void GetIdNameChecksInheritence() Assert.AreEqual("Id", parentDefinition.GetIdName()); } - [TestMethod] - public void TraverseMapping() - { - var definition = EntityMapping.RegisterType(typeof(TraverseMappingModel)); - var result = definition.TraverseProperties().ToArray(); - - Assert.AreEqual(32, result.Length); - - Assert.IsTrue(result.Any(m => m.FullPath == "RecursionType")); - - Assert.IsTrue(result.Any(m => m.FullPath == "NestedModel.PropertyOne")); - Assert.IsTrue(result.Any(m => m.FullPath == "NestedModel.InnerModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "NestedModel.InnerModel.InnerMostProperty")); - Assert.IsTrue(result.Any(m => m.FullPath == "NestedModel.InnerModel.NestedRecursionType")); - - Assert.IsTrue(result.Any(m => m.FullPath == "RepeatedType.PropertyOne")); - Assert.IsTrue(result.Any(m => m.FullPath == "RepeatedType.InnerModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "RepeatedType.InnerModel.InnerMostProperty")); - Assert.IsTrue(result.Any(m => m.FullPath == "RepeatedType.InnerModel.NestedRecursionType")); - - Assert.IsTrue(result.Any(m => m.FullPath == "ArrayModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "ArrayModel.InnerModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "ArrayModel.InnerModel.InnerMostProperty")); - Assert.IsTrue(result.Any(m => m.FullPath == "ArrayModel.InnerModel.NestedRecursionType")); - - Assert.IsTrue(result.Any(m => m.FullPath == "EnumerableModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "EnumerableModel.InnerModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "EnumerableModel.InnerModel.InnerMostProperty")); - Assert.IsTrue(result.Any(m => m.FullPath == "EnumerableModel.InnerModel.NestedRecursionType")); - - Assert.IsTrue(result.Any(m => m.FullPath == "ListModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "ListModel.InnerModel")); - Assert.IsTrue(result.Any(m => m.FullPath == "ListModel.InnerModel.InnerMostProperty")); - Assert.IsTrue(result.Any(m => m.FullPath == "ListModel.InnerModel.NestedRecursionType")); - } - [TestMethod] public void GetInheritedPropertiesTakesBaseProperties() { diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/PropertyTraversalExtensionTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/PropertyTraversalExtensionTests.cs new file mode 100644 index 00000000..6c601e1d --- /dev/null +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/PropertyTraversalExtensionTests.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MongoFramework.Infrastructure.Mapping; + +namespace MongoFramework.Tests.Infrastructure.Mapping; + +[TestClass] +public class PropertyTraversalExtensionTests : TestBase +{ + public class TraverseMappingModel + { + public string Id { get; set; } + public NestedTraverseMappingModel NestedModel { get; set; } + public NestedTraverseMappingModel RepeatedType { get; set; } + public TraverseMappingModel RecursionType { get; set; } + + public NestedTraverseMappingModel[] ArrayModel { get; set; } + public IEnumerable EnumerableModel { get; set; } + public List ListModel { get; set; } + + } + public class NestedTraverseMappingModel + { + public string PropertyOne { get; set; } + public int PropertyTwo { get; set; } + public InnerNestedTraverseMappingModel InnerModel { get; set; } + } + public class InnerNestedTraverseMappingModel + { + public string InnerMostProperty { get; set; } + public TraverseMappingModel NestedRecursionType { get; set; } + } + + [TestMethod] + public void TraverseProperties() + { + var definition = EntityMapping.RegisterType(typeof(TraverseMappingModel)); + var result = definition.TraverseProperties().ToArray(); + + Assert.AreEqual(32, result.Length); + + Assert.IsTrue(result.Any(m => m.GetPath() == "RecursionType" && m.Depth == 0)); + + Assert.IsTrue(result.Any(m => m.GetPath() == "NestedModel.PropertyOne" && m.Depth == 1)); + Assert.IsTrue(result.Any(m => m.GetPath() == "NestedModel.InnerModel" && m.Depth == 1)); + Assert.IsTrue(result.Any(m => m.GetPath() == "NestedModel.InnerModel.InnerMostProperty" && m.Depth == 2)); + Assert.IsTrue(result.Any(m => m.GetPath() == "NestedModel.InnerModel.NestedRecursionType" && m.Depth == 2)); + + Assert.IsTrue(result.Any(m => m.GetPath() == "RepeatedType.PropertyOne" && m.Depth == 1)); + Assert.IsTrue(result.Any(m => m.GetPath() == "RepeatedType.InnerModel" && m.Depth == 1)); + Assert.IsTrue(result.Any(m => m.GetPath() == "RepeatedType.InnerModel.InnerMostProperty" && m.Depth == 2)); + Assert.IsTrue(result.Any(m => m.GetPath() == "RepeatedType.InnerModel.NestedRecursionType" && m.Depth == 2)); + + Assert.IsTrue(result.Any(m => m.GetPath() == "ArrayModel" && m.Depth == 0)); + Assert.IsTrue(result.Any(m => m.GetPath() == "ArrayModel.InnerModel" && m.Depth == 1)); + Assert.IsTrue(result.Any(m => m.GetPath() == "ArrayModel.InnerModel.InnerMostProperty" && m.Depth == 2)); + Assert.IsTrue(result.Any(m => m.GetPath() == "ArrayModel.InnerModel.NestedRecursionType" && m.Depth == 2)); + + Assert.IsTrue(result.Any(m => m.GetPath() == "EnumerableModel" && m.Depth == 0)); + Assert.IsTrue(result.Any(m => m.GetPath() == "EnumerableModel.InnerModel" && m.Depth == 1)); + Assert.IsTrue(result.Any(m => m.GetPath() == "EnumerableModel.InnerModel.InnerMostProperty" && m.Depth == 2)); + Assert.IsTrue(result.Any(m => m.GetPath() == "EnumerableModel.InnerModel.NestedRecursionType" && m.Depth == 2)); + + Assert.IsTrue(result.Any(m => m.GetPath() == "ListModel" && m.Depth == 0)); + Assert.IsTrue(result.Any(m => m.GetPath() == "ListModel.InnerModel" && m.Depth == 1)); + Assert.IsTrue(result.Any(m => m.GetPath() == "ListModel.InnerModel.InnerMostProperty" && m.Depth == 2)); + Assert.IsTrue(result.Any(m => m.GetPath() == "ListModel.InnerModel.NestedRecursionType" && m.Depth == 2)); + } +} From 9f777b9ce45019726e012310f0e77b0044761e7f Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 22:29:27 +1030 Subject: [PATCH 07/10] Remove obsolete properties --- .../Infrastructure/Mapping/EntityDefinition.cs | 14 ++------------ .../Mapping/Processors/ExtraElementsProcessor.cs | 2 +- .../Mapping/Processors/NestedTypeProcessor.cs | 5 ++--- .../Mapping/Processors/PropertyMappingProcessor.cs | 4 +--- src/MongoFramework/MongoDbBucketSet.cs | 2 +- .../Mapping/EntityDefinitionExtensionTests.cs | 4 ++-- 6 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs index 49578697..8a040373 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs @@ -17,15 +17,8 @@ public interface IEntityDefinition public interface IEntityPropertyDefinition { - [Obsolete("Replace with IEntityDefinition _if_ actually needed")] - public Type EntityType { get; } - [Obsolete("Key is defined on IEntityDefinition")] - public bool IsKey { get; } + public IEntityDefinition EntityDefinition { get; } public string ElementName { get; } - [Obsolete("This should be on a custom EntityProperty type (WalkedEntityProperty)?")] - public string FullPath { get; } - [Obsolete("This is accessible from PropertyInfo")] - public Type PropertyType { get; } public PropertyInfo PropertyInfo { get; } public object GetValue(object entity); @@ -72,11 +65,8 @@ public class EntityDefinition : IEntityDefinition public class EntityPropertyDefinition : IEntityPropertyDefinition { - public Type EntityType { get; set; } - public bool IsKey { get; set; } + public IEntityDefinition EntityDefinition { get; set; } public string ElementName { get; set; } - public string FullPath { get; set; } - public Type PropertyType { get; set; } public PropertyInfo PropertyInfo { get; set; } public object GetValue(object entity) diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs index 61120651..71e969cd 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs @@ -27,7 +27,7 @@ public void ApplyMapping(IEntityDefinition definition) foreach (var property in definition.Properties) { var extraElementsAttribute = property.PropertyInfo.GetCustomAttribute(); - if (extraElementsAttribute != null && typeof(IDictionary).IsAssignableFrom(property.PropertyType)) + if (extraElementsAttribute != null && typeof(IDictionary).IsAssignableFrom(property.PropertyInfo.PropertyType)) { definition.ExtraElements = new EntityExtraElementsDefinition { diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs index f8637334..798562e9 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs @@ -1,5 +1,4 @@ -using MongoDB.Bson.Serialization; -using MongoFramework.Infrastructure.Internal; +using MongoFramework.Infrastructure.Internal; namespace MongoFramework.Infrastructure.Mapping.Processors { @@ -12,7 +11,7 @@ public void ApplyMapping(IEntityDefinition definition) foreach (var property in properties) { - var propertyType = property.PropertyType; + var propertyType = property.PropertyInfo.PropertyType; propertyType = propertyType.GetEnumerableItemTypeOrDefault(); //Maps the property type for handling property nesting diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs index 27ac3cf0..2b36fb63 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertyMappingProcessor.cs @@ -52,10 +52,8 @@ public void ApplyMapping(IEntityDefinition definition) definitionProperties.Add(new EntityPropertyDefinition { - EntityType = definition.EntityType, + EntityDefinition = definition, ElementName = elementName, - FullPath = elementName, - PropertyType = property.PropertyType, PropertyInfo = property }); } diff --git a/src/MongoFramework/MongoDbBucketSet.cs b/src/MongoFramework/MongoDbBucketSet.cs index 410e8252..ce2d47eb 100644 --- a/src/MongoFramework/MongoDbBucketSet.cs +++ b/src/MongoFramework/MongoDbBucketSet.cs @@ -40,7 +40,7 @@ public MongoDbBucketSet(IMongoDbContext context, IDbSetOptions options) throw new ArgumentException($"Property {bucketOptions.EntityTimeProperty} doesn't exist on bucket item."); } - if (property.PropertyType != typeof(DateTime)) + if (property.PropertyInfo.PropertyType != typeof(DateTime)) { throw new ArgumentException($"Property {bucketOptions.EntityTimeProperty} on bucket item isn't of type DateTime"); } diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs index d3a04982..24cfc12e 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs @@ -57,7 +57,7 @@ public void GetInheritedPropertiesTakesBaseProperties() var definition = EntityMapping.RegisterType(typeof(OverridePropertyGrandChildModel)); var inheritedProperties = definition.GetInheritedProperties().ToArray(); Assert.AreEqual(1, inheritedProperties.Length); - Assert.AreEqual(typeof(OverridePropertyBaseModel), inheritedProperties[0].EntityType); + Assert.AreEqual(typeof(OverridePropertyBaseModel), inheritedProperties[0].EntityDefinition.EntityType); } [TestMethod] public void GetAllPropertiesTakesBaseProperties() @@ -65,7 +65,7 @@ public void GetAllPropertiesTakesBaseProperties() var definition = EntityMapping.RegisterType(typeof(OverridePropertyChildModel)); var allProperties = definition.GetAllProperties().ToArray(); Assert.AreEqual(1, allProperties.Length); - Assert.AreEqual(typeof(OverridePropertyBaseModel), allProperties[0].EntityType); + Assert.AreEqual(typeof(OverridePropertyBaseModel), allProperties[0].EntityDefinition.EntityType); } [TestMethod] From ac18657588b0e9d8429fa8755df89e971c369bdd Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 22:58:53 +1030 Subject: [PATCH 08/10] Move some processors to hard abstraction rules These are now considered non-optional and cleans up some default assumptions --- .../Infrastructure/DriverAbstractionRules.cs | 38 +++++++++++++++++++ .../Mapping/DefaultMappingPack.cs | 2 - .../Infrastructure/Mapping/EntityMapping.cs | 2 + .../DecimalSerializationProcessor.cs | 21 ---------- .../Processors/TypeDiscoveryProcessor.cs | 19 ---------- 5 files changed, 40 insertions(+), 42 deletions(-) create mode 100644 src/MongoFramework/Infrastructure/DriverAbstractionRules.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs diff --git a/src/MongoFramework/Infrastructure/DriverAbstractionRules.cs b/src/MongoFramework/Infrastructure/DriverAbstractionRules.cs new file mode 100644 index 00000000..e5ea0623 --- /dev/null +++ b/src/MongoFramework/Infrastructure/DriverAbstractionRules.cs @@ -0,0 +1,38 @@ +using System; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Bson.Serialization; +using MongoDB.Bson; +using System.Diagnostics; +using MongoFramework.Infrastructure.Serialization; + +namespace MongoFramework.Infrastructure; + +/// +/// Provides a single entry point to configure common areas of the driver for MongoFramework +/// +internal static class DriverAbstractionRules +{ + public static void ApplyRules() + { + RegisterSerializer(new DecimalSerializer(BsonType.Decimal128)); + RegisterSerializer(new NullableSerializer(new DecimalSerializer(BsonType.Decimal128))); + + BsonSerializer.RegisterSerializationProvider(TypeDiscoverySerializationProvider.Instance); + } + + private static void RegisterSerializer(IBsonSerializer serializer) + { + try + { + BsonSerializer.RegisterSerializer(typeof(TTarget), serializer); + } + catch (BsonSerializationException ex) when (ex.Message.Contains("already a serializer registered")) + { + // Already registered + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message, "MongoFramework"); + } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs b/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs index b786320a..b7e7f0e7 100644 --- a/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs +++ b/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs @@ -13,8 +13,6 @@ public static class DefaultProcessors new EntityIdProcessor(), new NestedTypeProcessor(), new ExtraElementsProcessor(), - new DecimalSerializationProcessor(), - new TypeDiscoveryProcessor(), new BsonKnownTypesProcessor(), new IndexProcessor(), new MappingAdapterProcessor() diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs index 5a3c9245..2f31a2ed 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs @@ -17,6 +17,8 @@ public static class EntityMapping static EntityMapping() { + DriverAbstractionRules.ApplyRules(); + EntityDefinitions = new ConcurrentDictionary(); MappingProcessors = new List(); diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs deleted file mode 100644 index d3778f0b..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/DecimalSerializationProcessor.cs +++ /dev/null @@ -1,21 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization; -using MongoDB.Bson.Serialization.Serializers; - -namespace MongoFramework.Infrastructure.Mapping.Processors -{ - public class DecimalSerializationProcessor : IMappingProcessor - { - private bool SerializerAdded { get; set; } - - public void ApplyMapping(IEntityDefinition definition) - { - if (!SerializerAdded) - { - SerializerAdded = true; - BsonSerializer.RegisterSerializer(typeof(decimal), new DecimalSerializer(BsonType.Decimal128)); - BsonSerializer.RegisterSerializer(typeof(decimal?), new NullableSerializer(new DecimalSerializer(BsonType.Decimal128))); - } - } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs deleted file mode 100644 index 50d42bd7..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs +++ /dev/null @@ -1,19 +0,0 @@ -using MongoDB.Bson.Serialization; -using MongoFramework.Infrastructure.Serialization; - -namespace MongoFramework.Infrastructure.Mapping.Processors -{ - public class TypeDiscoveryProcessor : IMappingProcessor - { - private bool ProviderAdded { get; set; } - - public void ApplyMapping(IEntityDefinition definition) - { - if (!ProviderAdded) - { - ProviderAdded = true; - BsonSerializer.RegisterSerializationProvider(TypeDiscoverySerializationProvider.Instance); - } - } - } -} From a16bd701bebac3e83c9f47cda1549d66fa91a202 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 23:25:02 +1030 Subject: [PATCH 09/10] Type discovery fixes --- .../TypeDiscoverySerializationProvider.cs | 5 +- .../Processors/TypeDiscoveryProcessorTests.cs | 48 ------------------- .../TypeDiscoverySerializationTests.cs | 30 +++++------- .../MongoDbDriverHelper.cs | 8 ---- 4 files changed, 12 insertions(+), 79 deletions(-) delete mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs diff --git a/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializationProvider.cs b/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializationProvider.cs index 166ea364..e09b966b 100644 --- a/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializationProvider.cs +++ b/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializationProvider.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using MongoDB.Bson.Serialization; using MongoFramework.Attributes; using MongoFramework.Utilities; @@ -10,13 +9,11 @@ public class TypeDiscoverySerializationProvider : BsonSerializationProviderBase { public static TypeDiscoverySerializationProvider Instance { get; } = new TypeDiscoverySerializationProvider(); - public bool Enabled { get; set; } = true; - public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry) { Check.NotNull(type, nameof(type)); - if (Enabled && (type.GetCustomAttribute() != null || type == typeof(object))) + if (Attribute.IsDefined(type, typeof(RuntimeTypeDiscoveryAttribute)) || type == typeof(object)) { var serializerType = typeof(TypeDiscoverySerializer<>).MakeGenericType(type); return (IBsonSerializer)Activator.CreateInstance(serializerType); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs deleted file mode 100644 index fb0c4c27..00000000 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MongoDB.Bson.Serialization; -using MongoFramework.Attributes; -using MongoFramework.Infrastructure.Mapping; -using MongoFramework.Infrastructure.Mapping.Processors; -using MongoFramework.Infrastructure.Serialization; - -namespace MongoFramework.Tests.Infrastructure.Mapping.Processors -{ - [TestClass] - public class TypeDiscoveryProcessorTests : MappingTestBase - { - public class NoTypeDiscoveryAttributeModel - { - - } - - [RuntimeTypeDiscovery] - public class TypeDiscoveryAttributeModel - { - - } - - [TestMethod] - public void TypeDiscoverySerializerWhenAttributeIsDefined() - { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); - EntityMapping.AddMappingProcessor(new PropertyMappingProcessor()); - - EntityMapping.RegisterType(typeof(TypeDiscoveryAttributeModel)); - - var serializer = BsonSerializer.LookupSerializer(); - Assert.AreEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); - } - - [TestMethod] - public void NotTypeDiscoverySerializerWhenAttributeNotDefined() - { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); - EntityMapping.AddMappingProcessor(new PropertyMappingProcessor()); - - EntityMapping.RegisterType(typeof(NoTypeDiscoveryAttributeModel)); - - var serializer = BsonSerializer.LookupSerializer(); - Assert.AreNotEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); - } - } -} diff --git a/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoverySerializationTests.cs b/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoverySerializationTests.cs index e33b3d74..c368ccfc 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoverySerializationTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoverySerializationTests.cs @@ -46,10 +46,16 @@ public class UnknownDictionaryValueModel public IDictionary Dictionary { get; set; } } + public class NoTypeDiscovery_KnownBaseModel + { + } + public class NoTypeDiscovery_UnknownChildModel : NoTypeDiscovery_KnownBaseModel + { + } + [TestMethod] public void NullDeserialization() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(KnownBaseModel)); var serializer = TypeDiscoverySerializationProvider.Instance.GetSerializer(typeof(KnownBaseModel)); @@ -78,7 +84,6 @@ public void NullDeserialization() [TestMethod] public void DeserializeChildTypeDiscoveryForRootEntity() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(KnownBaseModel)); var document = new BsonDocument @@ -93,7 +98,6 @@ public void DeserializeChildTypeDiscoveryForRootEntity() [TestMethod] public void DeserializeGrandChildTypeDiscoveryForRootEntity() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(KnownBaseModel)); var document = new BsonDocument @@ -108,26 +112,21 @@ public void DeserializeGrandChildTypeDiscoveryForRootEntity() [TestMethod] public void DeserializeWithoutTypeDiscovery() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); - EntityMapping.RegisterType(typeof(KnownBaseModel)); - - TypeDiscoverySerializationProvider.Instance.Enabled = false; + //This test primarily confirms the behaviour of the driver without type discovery + EntityMapping.RegisterType(typeof(NoTypeDiscovery_KnownBaseModel)); var document = new BsonDocument { { "_t", "UnknownChildModel" } }; - var deserializedResult = BsonSerializer.Deserialize(document); - Assert.IsNotInstanceOfType(deserializedResult, typeof(UnknownChildModel)); - - TypeDiscoverySerializationProvider.Instance.Enabled = true; + var deserializedResult = BsonSerializer.Deserialize(document); + Assert.IsNotInstanceOfType(deserializedResult, typeof(NoTypeDiscovery_UnknownChildModel)); } [TestMethod] public void DeserializeCollection() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(CollectionBaseModel)); var document = new BsonDocument @@ -162,7 +161,6 @@ public void DeserializeCollection() [TestMethod] public void ReserializationWithoutDataLoss() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(CollectionBaseModel)); var initialEntity = new CollectionBaseModel @@ -193,7 +191,6 @@ public void ReserializationWithoutDataLoss() [TestMethod] public void DeserializeNullForUnknownPropertyType() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(UnknownPropertyTypeSerializationModel)); var document = new BsonDocument @@ -209,7 +206,6 @@ public void DeserializeNullForUnknownPropertyType() [TestMethod] public void DeserializeDictionaryForUnknownPropertyType() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(UnknownPropertyTypeSerializationModel)); var document = new BsonDocument @@ -235,7 +231,6 @@ public void DeserializeDictionaryForUnknownPropertyType() [TestMethod] public void DeserializeSpecifiedForUnknownPropertyType() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(UnknownPropertyTypeSerializationModel)); var document = new BsonDocument @@ -257,7 +252,6 @@ public void DeserializeSpecifiedForUnknownPropertyType() [TestMethod] public void DeserializeStringForUnknownPropertyType() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(UnknownPropertyTypeSerializationModel)); var document = new BsonDocument @@ -276,7 +270,6 @@ public void DeserializeStringForUnknownPropertyType() [TestMethod] public void DeserializeBooleanForUnknownPropertyType() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(UnknownPropertyTypeSerializationModel)); var document = new BsonDocument @@ -295,7 +288,6 @@ public void DeserializeBooleanForUnknownPropertyType() [TestMethod] public void DeserializeUnknownTypesInDictionary() { - EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); EntityMapping.RegisterType(typeof(UnknownDictionaryValueModel)); var document = new BsonDocument diff --git a/tests/MongoFramework.Tests/MongoDbDriverHelper.cs b/tests/MongoFramework.Tests/MongoDbDriverHelper.cs index 4b88677b..c542a143 100644 --- a/tests/MongoFramework.Tests/MongoDbDriverHelper.cs +++ b/tests/MongoFramework.Tests/MongoDbDriverHelper.cs @@ -38,14 +38,6 @@ public static void ResetDriver() { discriminators.Clear(); } - - var serializerRegistryField = typeof(BsonSerializer).GetField("__serializerRegistry", BindingFlags.NonPublic | BindingFlags.Static); - if (serializerRegistryField.GetValue(null) is BsonSerializerRegistry registry) - { - var cacheField = typeof(BsonSerializerRegistry).GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance); - var registryCache = cacheField.GetValue(registry) as ConcurrentDictionary; - registryCache.Clear(); - } } } } From ceec8b40d3c811f03ed717750f6305380514cf8a Mon Sep 17 00:00:00 2001 From: Turnerj Date: Wed, 28 Dec 2022 23:30:30 +1030 Subject: [PATCH 10/10] Fixing code quality issue --- .../Infrastructure/Mapping/EntityKeyGenerator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs b/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs index da1a256b..32395f91 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityKeyGenerator.cs @@ -9,14 +9,14 @@ public interface IEntityKeyGenerator public bool IsEmpty(object id); } -public class EntityKeyGenerators +public static class EntityKeyGenerators { public static readonly IEntityKeyGenerator StringKeyGenerator = new EntityKeyGenerator(StringObjectIdGenerator.Instance); public static readonly IEntityKeyGenerator GuidKeyGenerator = new EntityKeyGenerator(CombGuidGenerator.Instance); public static readonly IEntityKeyGenerator ObjectIdKeyGenerator = new EntityKeyGenerator(ObjectIdGenerator.Instance); } -internal class EntityKeyGenerator : IEntityKeyGenerator +internal sealed class EntityKeyGenerator : IEntityKeyGenerator { private readonly IIdGenerator idGenerator; @@ -36,7 +36,7 @@ public bool IsEmpty(object id) } } -internal class DriverKeyGeneratorWrapper : IIdGenerator +internal sealed class DriverKeyGeneratorWrapper : IIdGenerator { private readonly IEntityKeyGenerator entityKeyGenerator;