From 0fb6e3e7532ed5787fb55c59d01a3e02feceb259 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Sat, 11 May 2019 07:15:45 +0000 Subject: [PATCH 1/3] Initial writing commands --- .../Commands/AddEntityCommand.cs | 22 ++++++++++++ .../Infrastructure/Commands/IWriteCommand.cs | 12 +++++++ .../Commands/UpdateEntityCommand.cs | 34 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 src/MongoFramework/Infrastructure/Commands/AddEntityCommand.cs create mode 100644 src/MongoFramework/Infrastructure/Commands/IWriteCommand.cs create mode 100644 src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs diff --git a/src/MongoFramework/Infrastructure/Commands/AddEntityCommand.cs b/src/MongoFramework/Infrastructure/Commands/AddEntityCommand.cs new file mode 100644 index 00000000..3cb18bc3 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Commands/AddEntityCommand.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MongoDB.Driver; + +namespace MongoFramework.Infrastructure.Commands +{ + public class AddEntityCommand : IWriteCommand where TEntity : class + { + private EntityEntry EntityEntry { get; } + + public AddEntityCommand(EntityEntry entityEntry) + { + EntityEntry = entityEntry; + } + + public IEnumerable> GetModel() + { + yield return new InsertOneModel(EntityEntry.Entity); + } + } +} diff --git a/src/MongoFramework/Infrastructure/Commands/IWriteCommand.cs b/src/MongoFramework/Infrastructure/Commands/IWriteCommand.cs new file mode 100644 index 00000000..463e91f1 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Commands/IWriteCommand.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MongoDB.Driver; + +namespace MongoFramework.Infrastructure.Commands +{ + public interface IWriteCommand where TEntity : class + { + IEnumerable> GetModel(); + } +} diff --git a/src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs b/src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs new file mode 100644 index 00000000..6c996ea2 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MongoDB.Driver; +using MongoFramework.Infrastructure.DefinitionHelpers; + +namespace MongoFramework.Infrastructure.Commands +{ + public class UpdateEntityCommand : IWriteCommand where TEntity : class + { + private EntityEntry EntityEntry { get; } + + public UpdateEntityCommand(EntityEntry entityEntry) + { + EntityEntry = entityEntry; + } + + public IEnumerable> GetModel() + { + //var idFieldValue = EntityMapper.GetIdValue(entry.Entity); + //var filter = Builders.Filter.Eq(idFieldName, idFieldValue); + //var updateDefintion = UpdateDefinitionHelper.CreateFromDiff(EntityEntry.OriginalValues, EntityEntry.CurrentValues); + + ////MongoDB doesn't like it if an UpdateDefinition is empty. + ////This is primarily to work around a mutation that may set an entity to its default state. + //if (updateDefintion.HasChanges()) + //{ + // writeModel.Add(new UpdateOneModel(filter, updateDefintion)); + //} + //yield return new InsertOneModel(EntityEntry.Entity); + yield break; + } + } +} From c6ebe58d8f7cb7be133c95793db3301056562a08 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Sun, 12 May 2019 06:45:52 +0000 Subject: [PATCH 2/3] Initial core refactor of entity mapping system Code builds - tests not run --- README.md | 15 +- .../MiniProfilerDiagnosticListener.cs | 1 + .../Attributes/CreatedDateAttribute.cs | 3 +- .../Attributes/IncrementNumberAttribute.cs | 48 ---- .../Attributes/IndexAttribute.cs | 5 +- .../Attributes/MutatePropertyAttribute.cs | 7 +- .../Attributes/UpdatedDateAttribute.cs | 3 +- src/MongoFramework/IMongoDbConnection.cs | 6 +- .../Commands/UpdateEntityCommand.cs | 1 - .../UpdateDefinitionExtensions.cs | 1 + .../{ => Diagnostics}/DiagnosticCommand.cs | 2 +- .../NoOpDiagnosticListener.cs | 2 +- .../Infrastructure/EntityBucketCollection.cs | 7 +- .../Infrastructure/EntityChangeTracker.cs | 3 - .../Infrastructure/EntityCollection.cs | 24 +- .../EntityNavigationCollection.cs | 33 ++- .../Infrastructure/EntityReader.cs | 9 +- .../EntityRelationshipWriter.cs | 27 ++- .../EntityRelationships/EntityRelationship.cs | 13 - .../Infrastructure/EntityWriter.cs | 14 +- .../Infrastructure/IDiagnosticListener.cs | 3 +- .../IEntityNavigationCollection.cs | 3 +- .../IEntityRelationshipWriter.cs | 2 +- .../Indexing/DefaultIndexingPack.cs | 20 -- .../Infrastructure/Indexing/EntityIndexMap.cs | 9 - .../Indexing/EntityIndexMapper.cs | 58 ----- .../Indexing/EntityIndexWriter.cs | 24 +- .../Infrastructure/Indexing/IEntityIndex.cs | 9 - .../Indexing/IEntityIndexMap.cs | 9 - .../Indexing/IEntityIndexMapper.cs | 12 - .../Indexing/IEntityIndexMapperFactory.cs | 9 - .../Indexing/IIndexingProcessor.cs | 10 - .../Indexing/IIndexingProcessorPack.cs | 9 - .../Indexing/IndexModelBuilder.cs | 59 +++++ .../Processors/BasicIndexProcessor.cs | 58 ----- .../{ => Internal}/ReflectionExtensions.cs | 2 +- .../EntityProcessorCollection.cs | 6 +- .../Infrastructure/Linq/ILinqProcessor.cs | 2 +- .../Linq/IMongoFrameworkQueryProvider.cs | 1 - .../Linq/IMongoFrameworkQueryable.cs | 3 +- .../Linq/MongoFrameworkQueryProvider.cs | 3 +- .../Linq/MongoFrameworkQueryable.cs | 14 +- .../Processors/EntityMutationProcessor.cs | 11 +- .../Processors/EntityTrackingProcessor.cs | 2 +- .../Mapping/DefaultMappingPack.cs | 7 +- .../Mapping/EntityDefinition.cs | 15 ++ .../Mapping/EntityDefinitionExtensions.cs | 111 +++++++++ .../Infrastructure/Mapping/EntityIndex.cs | 12 + .../Infrastructure/Mapping/EntityMapper.cs | 205 ---------------- .../Infrastructure/Mapping/EntityMapping.cs | 126 ++++++++++ .../Infrastructure/Mapping/EntityProperty.cs | 30 +++ .../Mapping/EntityPropertyMap.cs | 15 -- .../Mapping/EntityRelationship.cs | 13 + .../Mapping/IEntityDefinition.cs | 14 ++ .../Infrastructure/Mapping/IEntityIndex.cs | 12 + .../Infrastructure/Mapping/IEntityMapper.cs | 16 -- .../Mapping/IEntityMapperFactory.cs | 9 - ...ntityPropertyMap.cs => IEntityProperty.cs} | 7 +- .../Mapping/IEntityRelationship.cs | 13 + .../Mapping/IMappingProcessor.cs | 2 +- .../Processors/BsonKnownTypesProcessor.cs | 8 +- .../Processors/CollectionNameProcessor.cs | 44 ++++ .../Mapping/Processors/EntityIdProcessor.cs | 6 +- .../EntityRelationshipProcessor.cs} | 54 +++-- .../Processors/ExtraElementsProcessor.cs | 4 +- .../Mapping/Processors/HierarchyProcessor.cs | 7 +- .../Mapping/Processors/IndexProcessor.cs | 26 ++ .../Processors/MappedPropertiesProcessor.cs | 3 +- .../Processors/NavigationPropertyProcessor.cs | 30 --- .../Processors/NestedPropertyProcessor.cs | 14 +- .../Mapping/Processors/PropertiesProcessor.cs | 25 ++ .../Processors/TypeDiscoveryProcessor.cs | 7 +- .../Mutators/EntityAttributeMutator.cs | 17 +- .../Mutators/NavigationPropertyMutator.cs | 16 +- .../EntityNavigationCollectionSerializer.cs | 25 +- .../TypeDiscoverySerializationProvider.cs | 15 +- .../Serialization/TypeDiscoverySerializer.cs | 14 +- src/MongoFramework/Linq/LinqExtensions.cs | 24 +- src/MongoFramework/MongoDbBucketSet.cs | 6 +- src/MongoFramework/MongoDbConnection.cs | 38 +-- src/MongoFramework/MongoDbSet.cs | 3 +- .../{Infrastructure => }/MongoDbUtility.cs | 2 +- .../EntityChangeTrackerTests.cs | 13 +- .../Infrastructure/EntityCollectionTests.cs | 33 +-- .../Infrastructure/EntityReaderTests.cs | 2 +- .../CollectionMappingTests.cs | 95 -------- ...ityNavigationCollectionIntegrationTests.cs | 2 +- .../EntityNavigationCollectionUnitTests.cs | 28 +-- .../SingleEntityIntegrationTests.cs | 3 +- .../SingleEntityMappingTests.cs | 129 ---------- .../Infrastructure/EntityWriterTests.cs | 12 +- .../Indexing/EntityIndexMapperTests.cs | 20 -- ...ssorTests.cs => IndexModelBuilderTests.cs} | 40 +--- .../Linq/MongoFrameworkQueryableTests.cs | 11 +- .../Mapping/EntityDefinitionExtensionTests.cs | 58 +++++ .../Mapping/EntityMapperTests.cs | 116 --------- .../Mapping/EntityMappingTests.cs | 34 +++ .../Infrastructure/Mapping/MappingTestBase.cs | 20 ++ ...sts.cs => BsonKnownTypesProcessorTests.cs} | 15 +- .../CollectionNameProcessorTests.cs | 55 +++++ .../Processors/EntityIdProcessorTests.cs | 41 ++-- .../EntityRelationshipProcessorTests.cs | 224 ++++++++++++++++++ .../Processors/ExtraElementsProcessorTests.cs | 34 ++- .../Processors/HierarchyProcessorTests.cs | 48 ++-- .../MappedPropertiesProcessorTests.cs | 27 +-- .../NestedPropertyProcessorTests.cs | 35 +-- .../Processors/TypeDiscoveryProcessorTests.cs | 31 ++- .../Mutators/IncrementNumberMutatorTests.cs | 71 ------ ...tityNavigationCollectionSerializerTests.cs | 35 +-- .../TypeDiscoveryIntegrationTests.cs | 28 +-- .../TypeDiscoverySerializationTests.cs | 31 +-- .../Linq/LinqExtensionsTests.cs | 6 +- .../MongoDbUtilityTests.cs | 2 +- .../MiniProfilerDiagnosticListenerTests.cs | 2 +- tests/MongoFramework.Tests/TestBase.cs | 15 +- .../MongoFramework.Tests/TestConfiguration.cs | 7 +- 116 files changed, 1359 insertions(+), 1521 deletions(-) delete mode 100644 src/MongoFramework/Attributes/IncrementNumberAttribute.cs rename src/MongoFramework/Infrastructure/{ => Diagnostics}/DiagnosticCommand.cs (94%) rename src/MongoFramework/Infrastructure/{ => Diagnostics}/NoOpDiagnosticListener.cs (80%) rename src/MongoFramework/Infrastructure/{EntityRelationships => }/EntityNavigationCollection.cs (68%) rename src/MongoFramework/Infrastructure/{EntityRelationships => }/EntityRelationshipWriter.cs (80%) delete mode 100644 src/MongoFramework/Infrastructure/EntityRelationships/EntityRelationship.cs rename src/MongoFramework/Infrastructure/{EntityRelationships => }/IEntityNavigationCollection.cs (79%) rename src/MongoFramework/Infrastructure/{EntityRelationships => }/IEntityRelationshipWriter.cs (86%) delete mode 100644 src/MongoFramework/Infrastructure/Indexing/DefaultIndexingPack.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/EntityIndexMap.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/EntityIndexMapper.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/IEntityIndex.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/IEntityIndexMap.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapper.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapperFactory.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/IIndexingProcessor.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/IIndexingProcessorPack.cs create mode 100644 src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs delete mode 100644 src/MongoFramework/Infrastructure/Indexing/Processors/BasicIndexProcessor.cs rename src/MongoFramework/Infrastructure/{ => Internal}/ReflectionExtensions.cs (95%) rename src/MongoFramework/Infrastructure/Linq/{Processors => }/EntityProcessorCollection.cs (57%) create mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityMapper.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityPropertyMap.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/EntityRelationship.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityMapper.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityMapperFactory.cs rename src/MongoFramework/Infrastructure/Mapping/{IEntityPropertyMap.cs => IEntityProperty.cs} (60%) create mode 100644 src/MongoFramework/Infrastructure/Mapping/IEntityRelationship.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs rename src/MongoFramework/Infrastructure/{EntityRelationships/EntityMapperExtensions.cs => Mapping/Processors/EntityRelationshipProcessor.cs} (50%) create mode 100644 src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs delete mode 100644 src/MongoFramework/Infrastructure/Mapping/Processors/NavigationPropertyProcessor.cs create mode 100644 src/MongoFramework/Infrastructure/Mapping/Processors/PropertiesProcessor.cs rename src/MongoFramework/Infrastructure/{EntityRelationships => Serialization}/EntityNavigationCollectionSerializer.cs (79%) rename src/MongoFramework/Infrastructure/{Mapping => }/Serialization/TypeDiscoverySerializationProvider.cs (64%) rename src/MongoFramework/Infrastructure/{Mapping => }/Serialization/TypeDiscoverySerializer.cs (93%) rename src/MongoFramework/{Infrastructure => }/MongoDbUtility.cs (90%) delete mode 100644 tests/MongoFramework.Tests/Infrastructure/EntityRelationships/CollectionMappingTests.cs delete mode 100644 tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityMappingTests.cs delete mode 100644 tests/MongoFramework.Tests/Infrastructure/Indexing/EntityIndexMapperTests.cs rename tests/MongoFramework.Tests/Infrastructure/Indexing/{Processors/BasicIndexProcessorTests.cs => IndexModelBuilderTests.cs} (64%) create mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs delete mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMapperTests.cs create mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMappingTests.cs create mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/MappingTestBase.cs rename tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/{BsonKnowTypesProcessorTests.cs => BsonKnownTypesProcessorTests.cs} (65%) create mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/CollectionNameProcessorTests.cs create mode 100644 tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs delete mode 100644 tests/MongoFramework.Tests/Infrastructure/Mutation/Mutators/IncrementNumberMutatorTests.cs rename tests/MongoFramework.Tests/Infrastructure/{EntityRelationships => Serialization}/EntityNavigationCollectionSerializerTests.cs (84%) rename tests/MongoFramework.Tests/Infrastructure/{Mapping => }/Serialization/TypeDiscoveryIntegrationTests.cs (53%) rename tests/MongoFramework.Tests/Infrastructure/{Mapping => }/Serialization/TypeDiscoverySerializationTests.cs (81%) rename tests/MongoFramework.Tests/{Infrastructure => }/MongoDbUtilityTests.cs (94%) diff --git a/README.md b/README.md index c62b857d..aba010b2 100644 --- a/README.md +++ b/README.md @@ -70,12 +70,8 @@ Populates the property with the current date/time on insert. _Note: The property Populates the property with the current date/time on update. _Note: The property must be of type `DateTime`_ -`[IncrementNumber(int incrementAmount = 1, bool onUpdateOnly = false)]` - -Updates the value of a property by the defined increment amount on insert or update. - ## Example -``` +```csharp using MongoFramework; using System.ComponentModel.DataAnnotations; @@ -88,16 +84,19 @@ public class MyEntity public class MyContext : MongoDbContext { - public MyContext() : base("MyContext") { } + public MyContext(IMongoDbConnection connection) : base(connection) { } public MongoDbSet MyEntities { get; set; } public MongoDbSet MyOtherEntities { get; set; } } -using (var myContext = new MyContext()) +... + +var connection = MongoDbConnection.FromConnectionString("YOUR_CONNECTION_STRING"); +using (var myContext = new MyContext(connection)) { var myEntity = myContext.MyEntities.Where(myEntity => myEntity.Name == "James").FirstOrDefault(); myEntity.Address = "123 SomeAddress Road, SomeSuburb"; - myContext.SaveChanges(); + await myContext.SaveChangesAsync(); } ``` diff --git a/src/MongoFramework.Profiling.MiniProfiler/MiniProfilerDiagnosticListener.cs b/src/MongoFramework.Profiling.MiniProfiler/MiniProfilerDiagnosticListener.cs index 92ad6feb..4787771c 100644 --- a/src/MongoFramework.Profiling.MiniProfiler/MiniProfilerDiagnosticListener.cs +++ b/src/MongoFramework.Profiling.MiniProfiler/MiniProfilerDiagnosticListener.cs @@ -7,6 +7,7 @@ using MongoDB.Bson.Serialization; using MongoDB.Driver; using MongoFramework.Infrastructure; +using MongoFramework.Infrastructure.Diagnostics; using StackExchange.Profiling; namespace MongoFramework.Profiling.MiniProfiler diff --git a/src/MongoFramework/Attributes/CreatedDateAttribute.cs b/src/MongoFramework/Attributes/CreatedDateAttribute.cs index a8e230ec..50f30a9c 100644 --- a/src/MongoFramework/Attributes/CreatedDateAttribute.cs +++ b/src/MongoFramework/Attributes/CreatedDateAttribute.cs @@ -1,12 +1,13 @@ using System; using System.Reflection; +using MongoFramework.Infrastructure.Mapping; namespace MongoFramework.Attributes { [AttributeUsage(AttributeTargets.Property)] public class CreatedDateAttribute : MutatePropertyAttribute { - public override void OnInsert(object target, PropertyInfo property) + public override void OnInsert(object target, IEntityProperty property) { if (property.PropertyType != typeof(DateTime)) { diff --git a/src/MongoFramework/Attributes/IncrementNumberAttribute.cs b/src/MongoFramework/Attributes/IncrementNumberAttribute.cs deleted file mode 100644 index dfec714c..00000000 --- a/src/MongoFramework/Attributes/IncrementNumberAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Reflection; - -namespace MongoFramework.Attributes -{ - [AttributeUsage(AttributeTargets.Property)] - public class IncrementNumberAttribute : MutatePropertyAttribute - { - public int IncrementAmount { get; private set; } - public bool OnUpdateOnly { get; private set; } - - public IncrementNumberAttribute() : this(false) { } - public IncrementNumberAttribute(bool onUpdateOnly) : this(1, onUpdateOnly) { } - - public IncrementNumberAttribute(int incrementAmount, bool onUpdateOnly = false) - { - IncrementAmount = incrementAmount; - OnUpdateOnly = onUpdateOnly; - } - - public override void OnInsert(object target, PropertyInfo property) - { - if (OnUpdateOnly) - { - return; - } - - IncrementTarget(target, property); - } - - public override void OnUpdate(object target, PropertyInfo property) - { - IncrementTarget(target, property); - } - - private void IncrementTarget(object target, PropertyInfo property) - { - if (property.PropertyType != typeof(int)) - { - throw new ArgumentException("Property is not of type Int"); - } - - var currentValue = (int)property.GetValue(target); - currentValue += IncrementAmount; - property.SetValue(target, currentValue); - } - } -} diff --git a/src/MongoFramework/Attributes/IndexAttribute.cs b/src/MongoFramework/Attributes/IndexAttribute.cs index c7c22d58..14e89e77 100644 --- a/src/MongoFramework/Attributes/IndexAttribute.cs +++ b/src/MongoFramework/Attributes/IndexAttribute.cs @@ -1,10 +1,9 @@ -using MongoFramework.Infrastructure.Indexing; -using System; +using System; namespace MongoFramework.Attributes { [AttributeUsage(AttributeTargets.Property)] - public class IndexAttribute : Attribute, IEntityIndex + public class IndexAttribute : Attribute { public string Name { get; private set; } public bool IsUnique { get; set; } diff --git a/src/MongoFramework/Attributes/MutatePropertyAttribute.cs b/src/MongoFramework/Attributes/MutatePropertyAttribute.cs index ee20aad1..5f7ee8df 100644 --- a/src/MongoFramework/Attributes/MutatePropertyAttribute.cs +++ b/src/MongoFramework/Attributes/MutatePropertyAttribute.cs @@ -1,12 +1,13 @@ using System; using System.Reflection; +using MongoFramework.Infrastructure.Mapping; namespace MongoFramework.Attributes { public abstract class MutatePropertyAttribute : Attribute { - public virtual void OnInsert(object target, PropertyInfo property) { } - public virtual void OnUpdate(object target, PropertyInfo property) { } - public virtual void OnSelect(object target, PropertyInfo property) { } + public virtual void OnInsert(object target, IEntityProperty property) { } + public virtual void OnUpdate(object target, IEntityProperty property) { } + public virtual void OnSelect(object target, IEntityProperty property) { } } } diff --git a/src/MongoFramework/Attributes/UpdatedDateAttribute.cs b/src/MongoFramework/Attributes/UpdatedDateAttribute.cs index dca71f3b..8c6e04d3 100644 --- a/src/MongoFramework/Attributes/UpdatedDateAttribute.cs +++ b/src/MongoFramework/Attributes/UpdatedDateAttribute.cs @@ -1,12 +1,13 @@ using System; using System.Reflection; +using MongoFramework.Infrastructure.Mapping; namespace MongoFramework.Attributes { [AttributeUsage(AttributeTargets.Property)] public class UpdatedDateAttribute : CreatedDateAttribute { - public override void OnUpdate(object target, PropertyInfo property) + public override void OnUpdate(object target, IEntityProperty property) { if (property.PropertyType != typeof(DateTime)) { diff --git a/src/MongoFramework/IMongoDbConnection.cs b/src/MongoFramework/IMongoDbConnection.cs index 9b193156..d86c75bf 100644 --- a/src/MongoFramework/IMongoDbConnection.cs +++ b/src/MongoFramework/IMongoDbConnection.cs @@ -1,15 +1,13 @@ using System; using MongoDB.Driver; using MongoFramework.Infrastructure; -using MongoFramework.Infrastructure.Indexing; -using MongoFramework.Infrastructure.Mapping; namespace MongoFramework { - public interface IMongoDbConnection : IEntityMapperFactory, IEntityIndexMapperFactory, IDisposable + public interface IMongoDbConnection : IDisposable { IMongoClient Client { get; } IMongoDatabase GetDatabase(); - IDiagnosticListener DiagnosticListener { get; } + IDiagnosticListener DiagnosticListener { set; get; } } } diff --git a/src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs b/src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs index 6c996ea2..2a524220 100644 --- a/src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs +++ b/src/MongoFramework/Infrastructure/Commands/UpdateEntityCommand.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Text; using MongoDB.Driver; -using MongoFramework.Infrastructure.DefinitionHelpers; namespace MongoFramework.Infrastructure.Commands { diff --git a/src/MongoFramework/Infrastructure/DefinitionHelpers/UpdateDefinitionExtensions.cs b/src/MongoFramework/Infrastructure/DefinitionHelpers/UpdateDefinitionExtensions.cs index ac4ddc25..f000d481 100644 --- a/src/MongoFramework/Infrastructure/DefinitionHelpers/UpdateDefinitionExtensions.cs +++ b/src/MongoFramework/Infrastructure/DefinitionHelpers/UpdateDefinitionExtensions.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using MongoFramework.Infrastructure.Internal; namespace MongoFramework.Infrastructure.DefinitionHelpers { diff --git a/src/MongoFramework/Infrastructure/DiagnosticCommand.cs b/src/MongoFramework/Infrastructure/Diagnostics/DiagnosticCommand.cs similarity index 94% rename from src/MongoFramework/Infrastructure/DiagnosticCommand.cs rename to src/MongoFramework/Infrastructure/Diagnostics/DiagnosticCommand.cs index 3c79a695..35209c3b 100644 --- a/src/MongoFramework/Infrastructure/DiagnosticCommand.cs +++ b/src/MongoFramework/Infrastructure/Diagnostics/DiagnosticCommand.cs @@ -3,7 +3,7 @@ using MongoDB.Driver; using MongoFramework.Infrastructure.Linq; -namespace MongoFramework.Infrastructure +namespace MongoFramework.Infrastructure.Diagnostics { public abstract class DiagnosticCommand { diff --git a/src/MongoFramework/Infrastructure/NoOpDiagnosticListener.cs b/src/MongoFramework/Infrastructure/Diagnostics/NoOpDiagnosticListener.cs similarity index 80% rename from src/MongoFramework/Infrastructure/NoOpDiagnosticListener.cs rename to src/MongoFramework/Infrastructure/Diagnostics/NoOpDiagnosticListener.cs index 96c912cc..68b796af 100644 --- a/src/MongoFramework/Infrastructure/NoOpDiagnosticListener.cs +++ b/src/MongoFramework/Infrastructure/Diagnostics/NoOpDiagnosticListener.cs @@ -1,6 +1,6 @@ using System; -namespace MongoFramework.Infrastructure +namespace MongoFramework.Infrastructure.Diagnostics { public class NoOpDiagnosticListener : IDiagnosticListener { diff --git a/src/MongoFramework/Infrastructure/EntityBucketCollection.cs b/src/MongoFramework/Infrastructure/EntityBucketCollection.cs index 16a1c08f..b75e4764 100644 --- a/src/MongoFramework/Infrastructure/EntityBucketCollection.cs +++ b/src/MongoFramework/Infrastructure/EntityBucketCollection.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using MongoFramework.Infrastructure.Mapping; namespace MongoFramework.Infrastructure { @@ -9,16 +8,14 @@ public class EntityBucketCollection where TGroup : class { private Dictionary> SubEntityStaging { get; } private IEntityReader> EntityReader { get; } - private IEntityMapper EntityMapper { get; } public int BucketSize { get; } - public EntityBucketCollection(IEntityReader> entityReader, int bucketSize, IEntityMapper entityMapper) + public EntityBucketCollection(IEntityReader> entityReader, int bucketSize) { SubEntityStaging = new Dictionary>(new ShallowPropertyEqualityComparer()); EntityReader = entityReader; BucketSize = bucketSize; - EntityMapper = entityMapper; } public void AddEntity(TGroup group, TSubEntity entity) @@ -35,7 +32,7 @@ public void AddEntity(TGroup group, TSubEntity entity) public IEntityCollection> AsEntityCollection() { - var entityCollection = new EntityCollection>(EntityMapper); + var entityCollection = new EntityCollection>(); foreach (var grouping in SubEntityStaging) { diff --git a/src/MongoFramework/Infrastructure/EntityChangeTracker.cs b/src/MongoFramework/Infrastructure/EntityChangeTracker.cs index 1dff7e46..35877823 100644 --- a/src/MongoFramework/Infrastructure/EntityChangeTracker.cs +++ b/src/MongoFramework/Infrastructure/EntityChangeTracker.cs @@ -1,12 +1,9 @@ using System.Linq; -using MongoFramework.Infrastructure.Mapping; namespace MongoFramework.Infrastructure { public class EntityChangeTracker : EntityCollection, IEntityChangeTracker where TEntity : class { - public EntityChangeTracker(IEntityMapper entityMapper) : base(entityMapper) { } - public void DetectChanges() { var entries = Entries.Where(e => e.State == EntityEntryState.NoChanges || e.State == EntityEntryState.Updated); diff --git a/src/MongoFramework/Infrastructure/EntityCollection.cs b/src/MongoFramework/Infrastructure/EntityCollection.cs index 4fc9dd1a..0b61f490 100644 --- a/src/MongoFramework/Infrastructure/EntityCollection.cs +++ b/src/MongoFramework/Infrastructure/EntityCollection.cs @@ -10,11 +10,11 @@ public class EntityCollection : IEntityCollection where TEntit { protected List> Entries { get; } = new List>(); - private IEntityMapper EntityMapper { get; } + private IEntityDefinition EntityDefinition { get; } - public EntityCollection(IEntityMapper entityMapper) + public EntityCollection() { - EntityMapper = entityMapper; + EntityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity)); } public int Count => Entries.Count; @@ -23,8 +23,8 @@ public EntityCollection(IEntityMapper entityMapper) public EntityEntry GetEntry(TEntity entity) { - var entityId = EntityMapper.GetIdValue(entity); - var defaultIdValue = EntityMapper.GetDefaultId(); + var entityId = EntityDefinition.GetIdValue(entity); + var defaultIdValue = EntityDefinition.GetDefaultId(); foreach (var entry in Entries) { @@ -34,7 +34,7 @@ public EntityEntry GetEntry(TEntity entity) } else { - var entryEntityId = EntityMapper.GetIdValue(entry.Entity); + var entryEntityId = EntityDefinition.GetIdValue(entry.Entity); if (!Equals(entryEntityId, defaultIdValue) && entryEntityId.Equals(entityId)) { return entry; @@ -89,8 +89,16 @@ public void Clear() public void Add(TEntity item) { - //TODO: Check the ID value is a default value - if not, mark it as non-changed - Update(item, EntityEntryState.Added); + var defaultId = EntityDefinition.GetDefaultId(); + var entityId = EntityDefinition.GetIdValue(item); + if (Equals(entityId, defaultId)) + { + Update(item, EntityEntryState.Added); + } + else + { + Update(item, EntityEntryState.NoChanges); + } } public bool Contains(TEntity item) diff --git a/src/MongoFramework/Infrastructure/EntityRelationships/EntityNavigationCollection.cs b/src/MongoFramework/Infrastructure/EntityNavigationCollection.cs similarity index 68% rename from src/MongoFramework/Infrastructure/EntityRelationships/EntityNavigationCollection.cs rename to src/MongoFramework/Infrastructure/EntityNavigationCollection.cs index c595b4e3..127224f7 100644 --- a/src/MongoFramework/Infrastructure/EntityRelationships/EntityNavigationCollection.cs +++ b/src/MongoFramework/Infrastructure/EntityNavigationCollection.cs @@ -5,28 +5,28 @@ using System.Collections.Generic; using System.Linq; -namespace MongoFramework.Infrastructure.EntityRelationships +namespace MongoFramework.Infrastructure { public class EntityNavigationCollection : EntityCollection, IEntityNavigationCollection where TEntity : class { private IMongoDbConnection Connection { get; set; } - private IEntityMapper EntityMapper { get; } - private IEntityPropertyMap ForeignPropertyMap { get; } private HashSet UnloadedIds { get; } = new HashSet(); - public string ForeignKey { get; } + public IEntityProperty ForeignProperty { get; } public new int Count => LoadedCount + UnloadedCount; public int LoadedCount => Entries.Count; public int UnloadedCount => UnloadedIds.Count; - public EntityNavigationCollection(string foreignKey, IMongoDbConnection connection) : base(connection?.GetEntityMapper(typeof(TEntity))) + public EntityNavigationCollection(IEntityProperty foreignProperty) : base() { - ForeignKey = foreignKey ?? throw new ArgumentNullException(nameof(foreignKey)); - Connection = connection ?? throw new ArgumentNullException(nameof(connection)); - EntityMapper = connection.GetEntityMapper(typeof(TEntity)); - ForeignPropertyMap = EntityMapper.GetEntityMapping().Where(m => m.Property.Name == foreignKey).FirstOrDefault(); + ForeignProperty = foreignProperty ?? throw new ArgumentNullException(nameof(foreignProperty)); + } + + public void SetConnection(IMongoDbConnection connection) + { + Connection = connection; } public void AddForeignId(object foreignId) @@ -37,14 +37,13 @@ public void AddForeignId(object foreignId) } //Check the EntityId matches the known type for TEntity - if (!ForeignPropertyMap.PropertyType.Equals(foreignId.GetType())) + if (!ForeignProperty.PropertyType.Equals(foreignId.GetType())) { - throw new InvalidOperationException($"Type mismatch for foreign key. {foreignId.GetType()} specified however expected type {ForeignPropertyMap.PropertyType}"); + throw new InvalidOperationException($"Type mismatch for foreign key. {foreignId.GetType()} specified however expected type {ForeignProperty.PropertyType}"); } //Check the entity isn't already loaded - var foreignProperty = ForeignPropertyMap.Property; - if (!Entries.Any(e => Equals(foreignId, foreignProperty.GetValue(e.Entity)))) + if (!Entries.Any(e => Equals(foreignId, ForeignProperty.GetValue(e.Entity)))) { UnloadedIds.Add(foreignId); } @@ -66,7 +65,7 @@ public void LoadEntities() } var dbEntityReader = new EntityReader(Connection); - var entities = dbEntityReader.AsQueryable().WherePropertyMatches(ForeignKey, ForeignPropertyMap.PropertyType, UnloadedIds); + var entities = dbEntityReader.AsQueryable().WherePropertyMatches(ForeignProperty, UnloadedIds); foreach (var entity in entities) { @@ -78,7 +77,7 @@ public void LoadEntities() public IEnumerable GetForeignIds() { - var loadedEntityIds = Entries.Select(e => ForeignPropertyMap.Property.GetValue(e.Entity)); + var loadedEntityIds = Entries.Select(e => ForeignProperty.GetValue(e.Entity)); return loadedEntityIds.Concat(UnloadedIds); } @@ -98,7 +97,7 @@ public new IEnumerator GetEnumerator() if (UnloadedIds.Any()) { var dbEntityReader = new EntityReader(Connection); - var unloadedEntities = dbEntityReader.AsQueryable().WherePropertyMatches(ForeignKey, ForeignPropertyMap.PropertyType, UnloadedIds); + var unloadedEntities = dbEntityReader.AsQueryable().WherePropertyMatches(ForeignProperty, UnloadedIds); using (var unloadedEnumerator = unloadedEntities.GetEnumerator()) { @@ -110,7 +109,7 @@ public new IEnumerator GetEnumerator() Update(loadedEntity, EntityEntryState.NoChanges); //Remove from unloaded entity collection - var foreignId = ForeignPropertyMap.Property.GetValue(loadedEntity); + var foreignId = ForeignProperty.GetValue(loadedEntity); UnloadedIds.Remove(foreignId); yield return loadedEntity; diff --git a/src/MongoFramework/Infrastructure/EntityReader.cs b/src/MongoFramework/Infrastructure/EntityReader.cs index c4031a7b..e5788d98 100644 --- a/src/MongoFramework/Infrastructure/EntityReader.cs +++ b/src/MongoFramework/Infrastructure/EntityReader.cs @@ -10,25 +10,24 @@ namespace MongoFramework.Infrastructure public class EntityReader : IEntityReader where TEntity : class { public IMongoDbConnection Connection { get; } - public IEntityMapper EntityMapper { get; private set; } + private IEntityDefinition EntityDefinition { get; } public EntityReader(IMongoDbConnection connection) { Connection = connection ?? throw new ArgumentNullException(nameof(connection)); - EntityMapper = connection.GetEntityMapper(typeof(TEntity)); + EntityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity)); } private IMongoCollection GetCollection() { - var collectionName = EntityMapper.GetCollectionName(); - return Connection.GetDatabase().GetCollection(collectionName); + return Connection.GetDatabase().GetCollection(EntityDefinition.CollectionName); } public IQueryable AsQueryable() { var underlyingQueryable = GetCollection().AsQueryable(); var queryable = new MongoFrameworkQueryable(Connection, underlyingQueryable); - queryable.EntityProcessors.Add(new EntityMutationProcessor(Connection)); + queryable.EntityProcessors.Add(new EntityMutationProcessor()); return queryable; } } diff --git a/src/MongoFramework/Infrastructure/EntityRelationships/EntityRelationshipWriter.cs b/src/MongoFramework/Infrastructure/EntityRelationshipWriter.cs similarity index 80% rename from src/MongoFramework/Infrastructure/EntityRelationships/EntityRelationshipWriter.cs rename to src/MongoFramework/Infrastructure/EntityRelationshipWriter.cs index 59bf4bcc..ff97e653 100644 --- a/src/MongoFramework/Infrastructure/EntityRelationships/EntityRelationshipWriter.cs +++ b/src/MongoFramework/Infrastructure/EntityRelationshipWriter.cs @@ -3,19 +3,20 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using MongoFramework.Infrastructure.Mapping; -namespace MongoFramework.Infrastructure.EntityRelationships +namespace MongoFramework.Infrastructure { public class EntityRelationshipWriter : IEntityRelationshipWriter where TEntity : class { - private IEnumerable Relationships { get; } + private IEnumerable Relationships { get; } private IMongoDbConnection Connection { get; } public EntityRelationshipWriter(IMongoDbConnection connection) { Connection = connection; - Relationships = connection.GetEntityMapper(typeof(TEntity)).GetEntityRelationships(connection); + Relationships = EntityMapping.GetOrCreateDefinition(typeof(TEntity)).Relationships; } public void CommitEntityRelationships(IEnumerable entities) @@ -81,25 +82,25 @@ public async Task CommitEntityRelationshipsAsync(IEnumerable entities, private IEntityCollection BuildRelatedEntityCollection(EntityRelationship relationship, IEnumerable entities) where TRelatedEntity : class { - var entityMapper = Connection.GetEntityMapper(typeof(TRelatedEntity)); - var collection = new EntityCollection(entityMapper); + var definition = EntityMapping.GetOrCreateDefinition(typeof(TRelatedEntity)); + var collection = new EntityCollection(); - var defaultId = entityMapper.GetDefaultId(); + var defaultId = definition.GetDefaultId(); var relatedEntitiesToProcess = new List(); foreach (var entity in entities) { + var propertyInfo = relationship.NavigationProperty.PropertyInfo; if (relationship.IsCollection) { - if (relationship.NavigationProperty.GetValue(entity) is ICollection navigationCollection) + if (propertyInfo.GetValue(entity) is ICollection navigationCollection) { relatedEntitiesToProcess.AddRange(navigationCollection); } } else { - var relatedEntity = (TRelatedEntity)relationship.NavigationProperty.GetValue(entity); - if (relatedEntity != null) + if (propertyInfo.GetValue(entity) is TRelatedEntity relatedEntity) { relatedEntitiesToProcess.Add(relatedEntity); } @@ -108,7 +109,7 @@ public async Task CommitEntityRelationshipsAsync(IEnumerable entities, foreach (var relatedEntity in relatedEntitiesToProcess) { - var entityId = entityMapper.GetIdValue(relatedEntity); + var entityId = definition.GetIdValue(relatedEntity); if (Equals(entityId, defaultId)) { collection.Add(relatedEntity); @@ -120,13 +121,13 @@ public async Task CommitEntityRelationshipsAsync(IEnumerable entities, private void ApplyForeignKeyChanges(EntityRelationship relationship, IEnumerable entities) where TRelatedEntity : class { - var entityMapper = Connection.GetEntityMapper(typeof(TRelatedEntity)); - var defaultId = entityMapper.GetDefaultId(); + var definition = EntityMapping.GetOrCreateDefinition(typeof(TRelatedEntity)); + var defaultId = definition.GetDefaultId(); foreach (var entity in entities) { var relatedEntity = (TRelatedEntity)relationship.NavigationProperty.GetValue(entity); - var entityId = relatedEntity == null ? defaultId : entityMapper.GetIdValue(relatedEntity); + var entityId = relatedEntity == null ? defaultId : definition.GetIdValue(relatedEntity); relationship.IdProperty.SetValue(entity, entityId); } } diff --git a/src/MongoFramework/Infrastructure/EntityRelationships/EntityRelationship.cs b/src/MongoFramework/Infrastructure/EntityRelationships/EntityRelationship.cs deleted file mode 100644 index 1c49d4dd..00000000 --- a/src/MongoFramework/Infrastructure/EntityRelationships/EntityRelationship.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Reflection; - -namespace MongoFramework.Infrastructure.EntityRelationships -{ - public class EntityRelationship - { - public PropertyInfo IdProperty { get; set; } - public PropertyInfo NavigationProperty { get; set; } - public Type EntityType { get; set; } - public bool IsCollection { get; set; } - } -} diff --git a/src/MongoFramework/Infrastructure/EntityWriter.cs b/src/MongoFramework/Infrastructure/EntityWriter.cs index cc210d72..a81df3e1 100644 --- a/src/MongoFramework/Infrastructure/EntityWriter.cs +++ b/src/MongoFramework/Infrastructure/EntityWriter.cs @@ -1,5 +1,6 @@ using MongoDB.Driver; using MongoFramework.Infrastructure.DefinitionHelpers; +using MongoFramework.Infrastructure.Diagnostics; using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mutation; using System; @@ -13,23 +14,22 @@ namespace MongoFramework.Infrastructure public class EntityWriter : IEntityWriter where TEntity : class { public IMongoDbConnection Connection { get; } - public IEntityMapper EntityMapper { get; } + private IEntityDefinition EntityDefinition { get; } public EntityWriter(IMongoDbConnection connection) { Connection = connection ?? throw new ArgumentNullException(nameof(connection)); - EntityMapper = connection.GetEntityMapper(typeof(TEntity)); + EntityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity)); } private IMongoCollection GetCollection() { - var collectionName = EntityMapper.GetCollectionName(); - return Connection.GetDatabase().GetCollection(collectionName); + return Connection.GetDatabase().GetCollection(EntityDefinition.CollectionName); } private IEnumerable> BuildWriteModel(IEntityCollection entityCollection) { - var idFieldName = EntityMapper.GetIdName(); + var idFieldName = EntityDefinition.GetIdName(); var writeModel = new List>(); foreach (var entry in entityCollection.GetEntries()) @@ -42,7 +42,7 @@ private IEnumerable> BuildWriteModel(IEntityCollection.MutateEntity(entry.Entity, MutatorType.Update, Connection); - var idFieldValue = EntityMapper.GetIdValue(entry.Entity); + var idFieldValue = EntityDefinition.GetIdValue(entry.Entity); var filter = Builders.Filter.Eq(idFieldName, idFieldValue); var updateDefintion = UpdateDefinitionHelper.CreateFromDiff(entry.OriginalValues, entry.CurrentValues); @@ -55,7 +55,7 @@ private IEnumerable> BuildWriteModel(IEntityCollection.Filter.Eq(idFieldName, idFieldValue); writeModel.Add(new DeleteOneModel(filter)); } diff --git a/src/MongoFramework/Infrastructure/IDiagnosticListener.cs b/src/MongoFramework/Infrastructure/IDiagnosticListener.cs index caa06519..ada8803c 100644 --- a/src/MongoFramework/Infrastructure/IDiagnosticListener.cs +++ b/src/MongoFramework/Infrastructure/IDiagnosticListener.cs @@ -1,4 +1,5 @@ -using System; +using MongoFramework.Infrastructure.Diagnostics; +using System; namespace MongoFramework.Infrastructure { diff --git a/src/MongoFramework/Infrastructure/EntityRelationships/IEntityNavigationCollection.cs b/src/MongoFramework/Infrastructure/IEntityNavigationCollection.cs similarity index 79% rename from src/MongoFramework/Infrastructure/EntityRelationships/IEntityNavigationCollection.cs rename to src/MongoFramework/Infrastructure/IEntityNavigationCollection.cs index db8057a0..8584c3db 100644 --- a/src/MongoFramework/Infrastructure/EntityRelationships/IEntityNavigationCollection.cs +++ b/src/MongoFramework/Infrastructure/IEntityNavigationCollection.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; -namespace MongoFramework.Infrastructure.EntityRelationships +namespace MongoFramework.Infrastructure { public interface IEntityNavigationCollection { + void SetConnection(IMongoDbConnection connection); void AddForeignId(object foreignId); void AddForeignIds(IEnumerable foreignIds); void LoadEntities(); diff --git a/src/MongoFramework/Infrastructure/EntityRelationships/IEntityRelationshipWriter.cs b/src/MongoFramework/Infrastructure/IEntityRelationshipWriter.cs similarity index 86% rename from src/MongoFramework/Infrastructure/EntityRelationships/IEntityRelationshipWriter.cs rename to src/MongoFramework/Infrastructure/IEntityRelationshipWriter.cs index 599b3d4f..7450099b 100644 --- a/src/MongoFramework/Infrastructure/EntityRelationships/IEntityRelationshipWriter.cs +++ b/src/MongoFramework/Infrastructure/IEntityRelationshipWriter.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Threading.Tasks; -namespace MongoFramework.Infrastructure.EntityRelationships +namespace MongoFramework.Infrastructure { public interface IEntityRelationshipWriter where TEntity : class { diff --git a/src/MongoFramework/Infrastructure/Indexing/DefaultIndexingPack.cs b/src/MongoFramework/Infrastructure/Indexing/DefaultIndexingPack.cs deleted file mode 100644 index 324620ee..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/DefaultIndexingPack.cs +++ /dev/null @@ -1,20 +0,0 @@ -using MongoFramework.Infrastructure.Indexing.Processors; -using System.Collections.Generic; - -namespace MongoFramework.Infrastructure.Indexing -{ - public class DefaultIndexingPack : IIndexingProcessorPack - { - public IEnumerable Processors { get; private set; } - - private DefaultIndexingPack() - { - Processors = new List - { - new BasicIndexProcessor() - }; - } - - public static IIndexingProcessorPack Instance { get; } = new DefaultIndexingPack(); - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/EntityIndexMap.cs b/src/MongoFramework/Infrastructure/Indexing/EntityIndexMap.cs deleted file mode 100644 index e2931477..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/EntityIndexMap.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MongoFramework.Infrastructure.Indexing -{ - internal class EntityIndexMap : IEntityIndexMap - { - public string ElementName { get; set; } - public string FullPath { get; set; } - public IEntityIndex Index { get; set; } - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/EntityIndexMapper.cs b/src/MongoFramework/Infrastructure/Indexing/EntityIndexMapper.cs deleted file mode 100644 index 5b19290f..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/EntityIndexMapper.cs +++ /dev/null @@ -1,58 +0,0 @@ -using MongoFramework.Infrastructure.Mapping; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; - -namespace MongoFramework.Infrastructure.Indexing -{ - public class EntityIndexMapper : IEntityIndexMapper - { - public Type EntityType { get; private set; } - private IEntityMapper EntityMapper { get; set; } - - private static ConcurrentDictionary> EntityIndexCache { get; set; } - - static EntityIndexMapper() - { - EntityIndexCache = new ConcurrentDictionary>(); - } - - public EntityIndexMapper(IEntityMapper entityMapper) - { - EntityMapper = entityMapper ?? throw new ArgumentNullException(nameof(entityMapper)); - EntityType = entityMapper.EntityType; - } - - public string GetCollectionName() - { - return EntityMapper.GetCollectionName(); - } - - public IEnumerable GetIndexMapping() - { - return EntityIndexCache.GetOrAdd(EntityType, t => - { - return EntityMapper.TraverseMapping().SelectMany(m => - m.Property.GetCustomAttributes(typeof(IEntityIndex), false).Select(a => new EntityIndexMap - { - ElementName = m.ElementName, - FullPath = m.FullPath, - Index = a as IEntityIndex - }) - ); - }); - } - } - - public class EntityIndexMapper : EntityIndexMapper - { - public EntityIndexMapper(IEntityMapper entityMapper) : base(entityMapper) - { - if (typeof(TEntity) != entityMapper.EntityType) - { - throw new InvalidOperationException("Generic type does not match IDbEntityMapper's EntityType"); - } - } - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/EntityIndexWriter.cs b/src/MongoFramework/Infrastructure/Indexing/EntityIndexWriter.cs index f6e3e050..1468a95c 100644 --- a/src/MongoFramework/Infrastructure/Indexing/EntityIndexWriter.cs +++ b/src/MongoFramework/Infrastructure/Indexing/EntityIndexWriter.cs @@ -1,4 +1,6 @@ using MongoDB.Driver; +using MongoFramework.Infrastructure.Diagnostics; +using MongoFramework.Infrastructure.Mapping; using System; using System.Collections.Generic; using System.Linq; @@ -10,30 +12,22 @@ namespace MongoFramework.Infrastructure.Indexing public class EntityIndexWriter : IEntityIndexWriter where TEntity : class { private IMongoDbConnection Connection { get; } - private IEntityIndexMapper IndexMapper { get; set; } + private IEntityDefinition EntityDefinition { get; set; } public EntityIndexWriter(IMongoDbConnection connection) { Connection = connection; - IndexMapper = connection.GetIndexMapper(typeof(TEntity)); + EntityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity)); } private IMongoCollection GetCollection() { - var collectionName = IndexMapper.GetCollectionName(); - return Connection.GetDatabase().GetCollection(collectionName); + return Connection.GetDatabase().GetCollection(EntityDefinition.CollectionName); } - - private IEnumerable> GenerateIndexModel() - { - var indexMapping = IndexMapper.GetIndexMapping(); - var processors = DefaultIndexingPack.Instance.Processors; - return processors.SelectMany(d => d.BuildIndexModel(indexMapping)); - } - + public void ApplyIndexing() { - var indexModel = GenerateIndexModel(); + var indexModel = IndexModelBuilder.BuildModel(); if (indexModel.Any()) { var commandId = Guid.NewGuid(); @@ -71,9 +65,9 @@ public void ApplyIndexing() } } - public async Task ApplyIndexingAsync(CancellationToken cancellationToken = default(CancellationToken)) + public async Task ApplyIndexingAsync(CancellationToken cancellationToken = default) { - var indexModel = GenerateIndexModel(); + var indexModel = IndexModelBuilder.BuildModel(); if (indexModel.Any()) { var commandId = Guid.NewGuid(); diff --git a/src/MongoFramework/Infrastructure/Indexing/IEntityIndex.cs b/src/MongoFramework/Infrastructure/Indexing/IEntityIndex.cs deleted file mode 100644 index ec173c4b..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/IEntityIndex.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MongoFramework.Infrastructure.Indexing -{ - public interface IEntityIndex - { - string Name { get; } - bool IsUnique { get; } - IndexSortOrder SortOrder { get; } - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMap.cs b/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMap.cs deleted file mode 100644 index d7eb4c05..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMap.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MongoFramework.Infrastructure.Indexing -{ - public interface IEntityIndexMap - { - string ElementName { get; } - string FullPath { get; } - IEntityIndex Index { get; } - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapper.cs b/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapper.cs deleted file mode 100644 index e7124d40..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapper.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MongoFramework.Infrastructure.Indexing -{ - public interface IEntityIndexMapper - { - Type EntityType { get; } - string GetCollectionName(); - IEnumerable GetIndexMapping(); - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapperFactory.cs b/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapperFactory.cs deleted file mode 100644 index aa9857b8..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/IEntityIndexMapperFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace MongoFramework.Infrastructure.Indexing -{ - public interface IEntityIndexMapperFactory - { - IEntityIndexMapper GetIndexMapper(Type entityType); - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/IIndexingProcessor.cs b/src/MongoFramework/Infrastructure/Indexing/IIndexingProcessor.cs deleted file mode 100644 index 6926d8f1..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/IIndexingProcessor.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MongoDB.Driver; -using System.Collections.Generic; - -namespace MongoFramework.Infrastructure.Indexing -{ - public interface IIndexingProcessor - { - IEnumerable> BuildIndexModel(IEnumerable indexMapping) where TEntity : class; - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/IIndexingProcessorPack.cs b/src/MongoFramework/Infrastructure/Indexing/IIndexingProcessorPack.cs deleted file mode 100644 index 5cde99ff..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/IIndexingProcessorPack.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace MongoFramework.Infrastructure.Indexing -{ - public interface IIndexingProcessorPack - { - IEnumerable Processors { get; } - } -} diff --git a/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs b/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs new file mode 100644 index 00000000..0d172ad6 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MongoDB.Driver; +using MongoFramework.Infrastructure.Mapping; + +namespace MongoFramework.Infrastructure.Indexing +{ + public static class IndexModelBuilder + { + public static IEnumerable> BuildModel() + { + var indexBuilder = Builders.IndexKeys; + var indexes = EntityMapping.GetOrCreateDefinition(typeof(TEntity)).Indexes; + + var groupedIndexModels = indexes + .Select(d => new + { + d.IndexName, + d.IndexPriority, + IndexModel = GetBaseIndexModel(d) + }) + .OrderBy(m => m.IndexPriority) + .GroupBy(m => m.IndexName) + .ToArray(); + + foreach (var groupedModel in groupedIndexModels) + { + if (groupedModel.Key != null) + { + var keys = indexBuilder.Combine(groupedModel.Select(m => m.IndexModel.Keys)); + var options = groupedModel.FirstOrDefault().IndexModel.Options; + yield return new CreateIndexModel(keys, options); + } + else + { + foreach (var model in groupedModel) + { + yield return model.IndexModel; + } + } + } + } + private static CreateIndexModel GetBaseIndexModel(IEntityIndex indexDefinition) + { + var builder = Builders.IndexKeys; + var indexDefinitionModel = indexDefinition.SortOrder == IndexSortOrder.Ascending ? + builder.Ascending(indexDefinition.Property.FullPath) : builder.Descending(indexDefinition.Property.FullPath); + + return new CreateIndexModel(indexDefinitionModel, new CreateIndexOptions + { + Name = indexDefinition.IndexName, + Unique = indexDefinition.IsUnique, + Background = true + }); + } + } +} diff --git a/src/MongoFramework/Infrastructure/Indexing/Processors/BasicIndexProcessor.cs b/src/MongoFramework/Infrastructure/Indexing/Processors/BasicIndexProcessor.cs deleted file mode 100644 index 0942ca46..00000000 --- a/src/MongoFramework/Infrastructure/Indexing/Processors/BasicIndexProcessor.cs +++ /dev/null @@ -1,58 +0,0 @@ -using MongoDB.Driver; -using MongoFramework.Attributes; -using System.Collections.Generic; -using System.Linq; - -namespace MongoFramework.Infrastructure.Indexing.Processors -{ - public class BasicIndexProcessor : IIndexingProcessor - { - public IEnumerable> BuildIndexModel(IEnumerable indexMapping) where TEntity : class - { - var result = new List>(); - var indexBuilder = Builders.IndexKeys; - - var groupedIndexModels = indexMapping - .Where(m => m.Index is IndexAttribute) - .Select(m => new - { - m.Index.Name, - (m.Index as IndexAttribute).IndexPriority, - IndexModel = GetBaseIndexModel(m) - }) - .OrderBy(m => m.IndexPriority) - .GroupBy(m => m.Name) - .ToArray(); - - foreach (var groupedModel in groupedIndexModels) - { - if (groupedModel.Key != null) - { - var keys = indexBuilder.Combine(groupedModel.Select(m => m.IndexModel.Keys)); - var options = groupedModel.FirstOrDefault().IndexModel.Options; - result.Add(new CreateIndexModel(keys, options)); - } - else - { - result.AddRange(groupedModel.Select(m => m.IndexModel)); - } - } - - return result; - } - - private CreateIndexModel GetBaseIndexModel(IEntityIndexMap indexMap) - { - var index = indexMap.Index; - var builder = Builders.IndexKeys; - var indexDefinition = index.SortOrder == IndexSortOrder.Ascending ? builder.Ascending(indexMap.FullPath) : builder.Descending(indexMap.FullPath); - - return new CreateIndexModel(indexDefinition, new CreateIndexOptions - { - Name = index.Name, - Unique = index.IsUnique, - Background = true - }); - } - } -} diff --git a/src/MongoFramework/Infrastructure/ReflectionExtensions.cs b/src/MongoFramework/Infrastructure/Internal/ReflectionExtensions.cs similarity index 95% rename from src/MongoFramework/Infrastructure/ReflectionExtensions.cs rename to src/MongoFramework/Infrastructure/Internal/ReflectionExtensions.cs index d52ec45b..86e5d967 100644 --- a/src/MongoFramework/Infrastructure/ReflectionExtensions.cs +++ b/src/MongoFramework/Infrastructure/Internal/ReflectionExtensions.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Reflection; -namespace MongoFramework.Infrastructure +namespace MongoFramework.Infrastructure.Internal { internal static class ReflectionExtensions { diff --git a/src/MongoFramework/Infrastructure/Linq/Processors/EntityProcessorCollection.cs b/src/MongoFramework/Infrastructure/Linq/EntityProcessorCollection.cs similarity index 57% rename from src/MongoFramework/Infrastructure/Linq/Processors/EntityProcessorCollection.cs rename to src/MongoFramework/Infrastructure/Linq/EntityProcessorCollection.cs index 1439cfbe..84c464d1 100644 --- a/src/MongoFramework/Infrastructure/Linq/Processors/EntityProcessorCollection.cs +++ b/src/MongoFramework/Infrastructure/Linq/EntityProcessorCollection.cs @@ -1,14 +1,14 @@ using System.Collections.Generic; -namespace MongoFramework.Infrastructure.Linq.Processors +namespace MongoFramework.Infrastructure.Linq { public class EntityProcessorCollection : List>, ILinqProcessor where TEntity : class { - public void ProcessEntity(TEntity entity) + public void ProcessEntity(TEntity entity, IMongoDbConnection connection) { foreach (var processor in this) { - processor.ProcessEntity(entity); + processor.ProcessEntity(entity, connection); } } } diff --git a/src/MongoFramework/Infrastructure/Linq/ILinqProcessor.cs b/src/MongoFramework/Infrastructure/Linq/ILinqProcessor.cs index 535e22a6..6c066895 100644 --- a/src/MongoFramework/Infrastructure/Linq/ILinqProcessor.cs +++ b/src/MongoFramework/Infrastructure/Linq/ILinqProcessor.cs @@ -2,6 +2,6 @@ { public interface ILinqProcessor where TEntity : class { - void ProcessEntity(TEntity entity); + void ProcessEntity(TEntity entity, IMongoDbConnection connection); } } diff --git a/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryProvider.cs b/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryProvider.cs index 1990994b..10c0383d 100644 --- a/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryProvider.cs +++ b/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryProvider.cs @@ -1,5 +1,4 @@ using MongoDB.Driver.Linq; -using MongoFramework.Infrastructure.Linq.Processors; using System.Linq; namespace MongoFramework.Infrastructure.Linq diff --git a/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryable.cs b/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryable.cs index 829dc6bb..5dd2f6f4 100644 --- a/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryable.cs +++ b/src/MongoFramework/Infrastructure/Linq/IMongoFrameworkQueryable.cs @@ -1,5 +1,4 @@ -using MongoFramework.Infrastructure.Linq.Processors; -using System.Linq; +using System.Linq; namespace MongoFramework.Infrastructure.Linq { diff --git a/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryProvider.cs b/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryProvider.cs index 593d56e5..10d0b6c8 100644 --- a/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryProvider.cs +++ b/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryProvider.cs @@ -1,5 +1,4 @@ using MongoDB.Driver.Linq; -using MongoFramework.Infrastructure.Linq.Processors; using System; using System.Linq; using System.Linq.Expressions; @@ -38,7 +37,7 @@ public virtual object Execute(Expression expression) if (result is TEntity) { - EntityProcessors.ProcessEntity((TEntity)result); + EntityProcessors.ProcessEntity((TEntity)result, Connection); } return result; diff --git a/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs b/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs index 96c62aa9..078eaea8 100644 --- a/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs +++ b/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs @@ -1,5 +1,6 @@ using MongoDB.Driver.Linq; -using MongoFramework.Infrastructure.Linq.Processors; +using MongoFramework.Infrastructure.Diagnostics; +using MongoFramework.Infrastructure.Mapping; using System; using System.Collections; using System.Collections.Generic; @@ -82,12 +83,7 @@ public IEnumerator GetEnumerator() { while (enumerator.MoveNext()) { - var item = enumerator.Current; - if (item is TEntity) - { - EntityProcessors.ProcessEntity((TEntity)(object)item); - } - yield return item; + yield return enumerator.Current; } } } @@ -115,8 +111,8 @@ IEnumerator IEnumerable.GetEnumerator() public string ToQuery() { var executionModel = InternalProvider.UnderlyingQueryable.GetExecutionModel(); - var entityMapper = Connection.GetEntityMapper(typeof(TEntity)); - return $"db.{entityMapper.GetCollectionName()}.{executionModel}"; + var definition = EntityMapping.GetOrCreateDefinition(typeof(TEntity)); + return $"db.{definition.CollectionName}.{executionModel}"; } } } diff --git a/src/MongoFramework/Infrastructure/Linq/Processors/EntityMutationProcessor.cs b/src/MongoFramework/Infrastructure/Linq/Processors/EntityMutationProcessor.cs index 42b51287..9bf14a0d 100644 --- a/src/MongoFramework/Infrastructure/Linq/Processors/EntityMutationProcessor.cs +++ b/src/MongoFramework/Infrastructure/Linq/Processors/EntityMutationProcessor.cs @@ -4,16 +4,9 @@ namespace MongoFramework.Infrastructure.Linq.Processors { public class EntityMutationProcessor : ILinqProcessor where TEntity : class { - public IMongoDbConnection Connection { get; private set; } - - public EntityMutationProcessor(IMongoDbConnection connection) - { - Connection = connection; - } - - public void ProcessEntity(TEntity entity) + public void ProcessEntity(TEntity entity, IMongoDbConnection connection) { - EntityMutation.MutateEntity(entity, MutatorType.Select, Connection); + EntityMutation.MutateEntity(entity, MutatorType.Select, connection); } } } diff --git a/src/MongoFramework/Infrastructure/Linq/Processors/EntityTrackingProcessor.cs b/src/MongoFramework/Infrastructure/Linq/Processors/EntityTrackingProcessor.cs index 5f4f8716..2f404789 100644 --- a/src/MongoFramework/Infrastructure/Linq/Processors/EntityTrackingProcessor.cs +++ b/src/MongoFramework/Infrastructure/Linq/Processors/EntityTrackingProcessor.cs @@ -9,7 +9,7 @@ public EntityTrackingProcessor(IEntityChangeTracker changeSet) ChangeTracker = changeSet; } - public void ProcessEntity(TEntity entity) + public void ProcessEntity(TEntity entity, IMongoDbConnection connection) { ChangeTracker.Update(entity, EntityEntryState.NoChanges); } diff --git a/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs b/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs index 2f868d8b..5188a1a0 100644 --- a/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs +++ b/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs @@ -11,14 +11,17 @@ private DefaultMappingPack() { Processors = new List { + new CollectionNameProcessor(), new HierarchyProcessor(), new EntityIdProcessor(), new MappedPropertiesProcessor(), new NestedPropertyProcessor(), new ExtraElementsProcessor(), - new NavigationPropertyProcessor(), new TypeDiscoveryProcessor(), - new BsonKnownTypesProcessor() + new BsonKnownTypesProcessor(), + new PropertiesProcessor(), + new IndexProcessor(), + new EntityRelationshipProcessor() }; } diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs new file mode 100644 index 00000000..d4de6ce0 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MongoFramework.Infrastructure.Mapping +{ + public class EntityDefinition : IEntityDefinition + { + public Type EntityType { get; set; } + public string CollectionName { get; set; } + public IEnumerable Properties { get; set; } + public IEnumerable Relationships { get; set; } + public IEnumerable Indexes { get; set; } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs new file mode 100644 index 00000000..d636f213 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Reflection; +using System.Text; +using MongoDB.Bson; + +namespace MongoFramework.Infrastructure.Mapping +{ + public static class EntityDefinitionExtensions + { + public static IEntityProperty GetIdProperty(this IEntityDefinition definition) + { + return definition.Properties.Where(m => m.IsKey).FirstOrDefault(); + } + + public static string GetIdName(this IEntityDefinition definition) + { + return definition.Properties.Where(m => m.IsKey).Select(m => m.ElementName).FirstOrDefault(); + } + + public static object GetIdValue(this IEntityDefinition definition, object entity) + { + return definition.GetIdProperty()?.GetValue(entity); + } + + public static object GetDefaultId(this IEntityDefinition definition) + { + var idPropertyType = definition.GetIdProperty().PropertyType; + if (idPropertyType.IsValueType) + { + return Activator.CreateInstance(idPropertyType); + } + return null; + } + + public static IEnumerable GetInheritedProperties(this IEntityDefinition definition) + { + var currentType = definition.EntityType.BaseType; + while (currentType != typeof(object)) + { + var properties = EntityMapping.GetOrCreateDefinition(currentType).Properties; + foreach (var property in properties) + { + yield return property; + } + } + } + + public static IEnumerable GetAllProperties(this IEntityDefinition definition) + { + var localProperties = definition.Properties; + var inheritedProperties = definition.GetInheritedProperties(); + return localProperties.Concat(inheritedProperties); + } + + public static IEntityProperty GetProperty(this IEntityDefinition definition, string name) + { + return definition.GetAllProperties().Where(p => p.PropertyInfo.Name == name).FirstOrDefault(); + } + + private 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; + + if (property.PropertyType.IsClass && !state.SeenTypes.Contains(property.PropertyType)) + { + var nestedProperties = EntityMapping.GetOrCreateDefinition(property.PropertyType) + .GetAllProperties() + .Select(p => new EntityProperty + { + 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) + { + property.PropertyType + }, + Properties = nestedProperties + }); + } + } + } + } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs b/src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs new file mode 100644 index 00000000..b9aacb5e --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/EntityIndex.cs @@ -0,0 +1,12 @@ + +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; } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityMapper.cs b/src/MongoFramework/Infrastructure/Mapping/EntityMapper.cs deleted file mode 100644 index 0fb00bb7..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/EntityMapper.cs +++ /dev/null @@ -1,205 +0,0 @@ -using MongoDB.Bson.Serialization; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Reflection; -using System.Threading; - -namespace MongoFramework.Infrastructure.Mapping -{ - public class EntityMapper : IEntityMapper - { - public Type EntityType { get; private set; } - private BsonClassMap ClassMap { get; set; } - private IMongoDbConnection Connection { get; } - - private static ReaderWriterLockSlim MappingLock { get; } = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - private static ConcurrentDictionary> EntityMapCache { get; set; } - - static EntityMapper() - { - EntityMapCache = new ConcurrentDictionary>(); - } - - public EntityMapper(Type entityType, IMongoDbConnection connection) - { - EntityType = entityType ?? throw new ArgumentNullException("entityType"); - Connection = connection; - InitialiseClassMap(); - } - - private void InitialiseClassMap() - { - MappingLock.EnterUpgradeableReadLock(); - try - { - //For reasons unknown to me, you can't just call "BsonClassMap.LookupClassMap" as that "freezes" the class map - //Instead, you must do the lookup and initial creation yourself. - var classMaps = BsonClassMap.GetRegisteredClassMaps(); - ClassMap = classMaps.Where(cm => cm.ClassType == EntityType).FirstOrDefault(); - - if (ClassMap == null) - { - MappingLock.EnterWriteLock(); - try - { - ClassMap = new BsonClassMap(EntityType); - ClassMap.AutoMap(); - BsonClassMap.RegisterClassMap(ClassMap); - - foreach (var processor in DefaultMappingPack.Instance.Processors) - { - processor.ApplyMapping(EntityType, ClassMap, Connection); - } - } - finally - { - MappingLock.ExitWriteLock(); - } - } - } - finally - { - MappingLock.ExitUpgradeableReadLock(); - } - } - - public string GetCollectionName() - { - var tableAttribute = EntityType.GetCustomAttribute(); - - if (tableAttribute == null && EntityType.IsGenericType && EntityType.GetGenericTypeDefinition() == typeof(EntityBucket<,>)) - { - var groupProperty = EntityType.GetProperty("Group", BindingFlags.Public | BindingFlags.Instance); - tableAttribute = groupProperty.GetCustomAttribute(); - if (tableAttribute == null) - { - return groupProperty.PropertyType.Name; - } - } - - if (tableAttribute != null) - { - if (string.IsNullOrEmpty(tableAttribute.Schema)) - { - return tableAttribute.Name; - } - else - { - return tableAttribute.Schema + "." + tableAttribute.Name; - } - } - else - { - return EntityType.Name; - } - } - - public string GetIdName() - { - return GetEntityMapping().Where(m => m.IsKey).Select(m => m.ElementName).FirstOrDefault(); - } - - public object GetIdValue(object entity) - { - var idProperty = GetEntityMapping().Where(m => m.IsKey).Select(m => m.Property).FirstOrDefault(); - return idProperty?.GetValue(entity); - } - - public object GetDefaultId() - { - var idPropertyType = GetEntityMapping().Where(m => m.IsKey).Select(m => m.PropertyType).FirstOrDefault(); - if (idPropertyType.IsValueType) - { - return Activator.CreateInstance(idPropertyType); - } - return null; - } - - public IEnumerable GetEntityMapping() - { - return GetEntityMapping(true); - } - - private IEnumerable GetEntityMapping(bool includeInherited) - { - if (includeInherited && EntityType.BaseType != typeof(object)) - { - var declaredProperties = GetEntityMapping(false); - var inheritedProperties = new EntityMapper(EntityType.BaseType, Connection).GetEntityMapping(true); - return declaredProperties.Concat(inheritedProperties); - } - else - { - return EntityMapCache.GetOrAdd(EntityType, t => - { - return ClassMap.DeclaredMemberMaps.Select(m => new EntityPropertyMap - { - EntityType = t, - IsKey = m == ClassMap.IdMemberMap, - ElementName = m.ElementName, - FullPath = m.ElementName, - PropertyType = (m.MemberInfo as PropertyInfo).PropertyType, - Property = m.MemberInfo as PropertyInfo - }); - }); - } - } - - public IEnumerable TraverseMapping() - { - var stack = new Stack(); - stack.Push(new TraversalState - { - TypeHierarchy = new HashSet { EntityType }, - CurrentMap = GetEntityMapping() - }); - - while (stack.Count > 0) - { - var state = stack.Pop(); - foreach (var map in state.CurrentMap) - { - yield return map; - - if (map.PropertyType.IsClass && !state.TypeHierarchy.Contains(map.PropertyType)) - { - var nestedMapping = new EntityMapper(map.PropertyType, Connection) - .GetEntityMapping() - .Select(m => new EntityPropertyMap - { - EntityType = m.EntityType, - IsKey = m.IsKey, - ElementName = m.ElementName, - FullPath = $"{map.FullPath}.{m.ElementName}", - PropertyType = m.PropertyType, - Property = m.Property - }); - - stack.Push(new TraversalState - { - TypeHierarchy = new HashSet(state.TypeHierarchy) - { - map.PropertyType - }, - CurrentMap = nestedMapping - }); - } - } - } - } - - private class TraversalState - { - public HashSet TypeHierarchy { get; set; } - public IEnumerable CurrentMap { get; set; } - } - } - - public class EntityMapper : EntityMapper where TEntity : class - { - public EntityMapper(IMongoDbConnection connection) : base(typeof(TEntity), connection) { } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs new file mode 100644 index 00000000..4f3fa82a --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs @@ -0,0 +1,126 @@ +using MongoDB.Bson.Serialization; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Reflection; +using System.Threading; + +namespace MongoFramework.Infrastructure.Mapping +{ + public class EntityMapping + { + private static ReaderWriterLockSlim MappingLock { get; } = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + private static ConcurrentDictionary EntityDefinitions { get; } + private static ConcurrentDictionary MappingProcessors { get; } + + static EntityMapping() + { + EntityDefinitions = new ConcurrentDictionary(); + MappingProcessors = new ConcurrentDictionary(); + + AddMappingProcessors(DefaultMappingPack.Instance.Processors); + } + public static IEntityDefinition SetEntityDefinition(IEntityDefinition definition) + { + return EntityDefinitions.AddOrUpdate(definition.EntityType, definition, (entityType, existingValue) => + { + return definition; + }); + } + + public static void RemoveEntityDefinition(IEntityDefinition definition) + { + EntityDefinitions.TryRemove(definition.EntityType, out _); + } + + public static void RemoveAllDefinitions() + { + EntityDefinitions.Clear(); + } + + public static bool IsRegistered(Type entityType) + { + return EntityDefinitions.ContainsKey(entityType); + } + + public static IEntityDefinition RegisterType(Type entityType) + { + if (IsRegistered(entityType)) + { + throw new ArgumentException("Type is already registered", nameof(entityType)); + } + + var definition = new EntityDefinition + { + EntityType = entityType + }; + + MappingLock.EnterUpgradeableReadLock(); + try + { + //For reasons unknown to me, you can't just call "BsonClassMap.LookupClassMap" as that "freezes" the class map + //Instead, you must do the lookup and initial creation yourself. + var classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == entityType).FirstOrDefault(); + + if (classMap == null) + { + MappingLock.EnterWriteLock(); + + try + { + classMap = new BsonClassMap(entityType); + + BsonClassMap.RegisterClassMap(classMap); + classMap.AutoMap(); + + foreach (var processor in MappingProcessors.Values) + { + processor.ApplyMapping(definition, classMap); + } + } + finally + { + MappingLock.ExitWriteLock(); + } + } + } + finally + { + MappingLock.ExitUpgradeableReadLock(); + } + + return SetEntityDefinition(definition); + } + + public static IEntityDefinition GetOrCreateDefinition(Type entityType) + { + return EntityDefinitions.GetOrAdd(entityType, t => + { + return RegisterType(entityType); + }); + } + + public static void AddMappingProcessors(IEnumerable mappingProcessors) + { + foreach (var processor in mappingProcessors) + { + MappingProcessors.TryAdd(processor.GetType(), processor); + } + } + public static void AddMappingProcessor(TProcessor mappingProcessor) where TProcessor : IMappingProcessor + { + MappingProcessors.TryAdd(typeof(TProcessor), mappingProcessor); + } + public static void RemoveMappingProcessor() where TProcessor : IMappingProcessor + { + MappingProcessors.TryRemove(typeof(TProcessor), out _); + } + public static void RemoveAllMappingProcessors() + { + MappingProcessors.Clear(); + } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs b/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs new file mode 100644 index 00000000..3aaade37 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs @@ -0,0 +1,30 @@ +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); + } + + public override string ToString() + { + return $"{EntityType.Name}.{PropertyInfo.Name}"; + } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityPropertyMap.cs b/src/MongoFramework/Infrastructure/Mapping/EntityPropertyMap.cs deleted file mode 100644 index cf47128b..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/EntityPropertyMap.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Reflection; - -namespace MongoFramework.Infrastructure.Mapping -{ - internal class EntityPropertyMap : IEntityPropertyMap - { - 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 Property { get; set; } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityRelationship.cs b/src/MongoFramework/Infrastructure/Mapping/EntityRelationship.cs new file mode 100644 index 00000000..11b0f56c --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/EntityRelationship.cs @@ -0,0 +1,13 @@ +using System; +using System.Reflection; + +namespace MongoFramework.Infrastructure.Mapping +{ + public class EntityRelationship : IEntityRelationship + { + public IEntityProperty IdProperty { get; set; } + public IEntityProperty NavigationProperty { get; set; } + public Type EntityType { get; set; } + public bool IsCollection { get; set; } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs new file mode 100644 index 00000000..00bcd912 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/IEntityDefinition.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace MongoFramework.Infrastructure.Mapping +{ + public interface IEntityDefinition + { + Type EntityType { get; set; } + string CollectionName { get; set; } + IEnumerable Properties { get; set; } + IEnumerable Relationships { get; set; } + IEnumerable Indexes { get; set; } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs new file mode 100644 index 00000000..290576bf --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/IEntityIndex.cs @@ -0,0 +1,12 @@ + +namespace MongoFramework.Infrastructure.Mapping +{ + public interface IEntityIndex + { + IEntityProperty Property { get; set; } + string IndexName { get; set; } + bool IsUnique { get; set; } + IndexSortOrder SortOrder { get; set; } + int IndexPriority { get; set; } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityMapper.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityMapper.cs deleted file mode 100644 index 64ff8cbb..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityMapper.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MongoFramework.Infrastructure.Mapping -{ - public interface IEntityMapper - { - Type EntityType { get; } - string GetIdName(); - object GetIdValue(object entity); - object GetDefaultId(); - string GetCollectionName(); - IEnumerable GetEntityMapping(); - IEnumerable TraverseMapping(); - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityMapperFactory.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityMapperFactory.cs deleted file mode 100644 index 88a78c27..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityMapperFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace MongoFramework.Infrastructure.Mapping -{ - public interface IEntityMapperFactory - { - IEntityMapper GetEntityMapper(Type entityType); - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityPropertyMap.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs similarity index 60% rename from src/MongoFramework/Infrastructure/Mapping/IEntityPropertyMap.cs rename to src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs index e115334e..8c6bfecd 100644 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityPropertyMap.cs +++ b/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs @@ -3,13 +3,16 @@ namespace MongoFramework.Infrastructure.Mapping { - public interface IEntityPropertyMap + public interface IEntityProperty { Type EntityType { get; } bool IsKey { get; } string ElementName { get; } string FullPath { get; } Type PropertyType { get; } - PropertyInfo Property { get; } + PropertyInfo PropertyInfo { get; } + + object GetValue(object entity); + void SetValue(object entity, object value); } } diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityRelationship.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityRelationship.cs new file mode 100644 index 00000000..fa083702 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/IEntityRelationship.cs @@ -0,0 +1,13 @@ +using System; +using System.Reflection; + +namespace MongoFramework.Infrastructure.Mapping +{ + public interface IEntityRelationship + { + IEntityProperty IdProperty { get; set; } + IEntityProperty NavigationProperty { get; set; } + Type EntityType { get; set; } + bool IsCollection { get; set; } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs index 8512d8c5..36e4331d 100644 --- a/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/IMappingProcessor.cs @@ -5,6 +5,6 @@ namespace MongoFramework.Infrastructure.Mapping { public interface IMappingProcessor { - void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection); + void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap); } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs index b84e0ff4..39707d2b 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/BsonKnownTypesProcessor.cs @@ -7,14 +7,18 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class BsonKnownTypesProcessor : IMappingProcessor { - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { + var entityType = definition.EntityType; var bsonKnownTypesAttribute = entityType.GetCustomAttribute(); if (bsonKnownTypesAttribute != null) { foreach (var type in bsonKnownTypesAttribute.KnownTypes) { - connection.GetEntityMapper(type); + if (!EntityMapping.IsRegistered(type)) + { + EntityMapping.RegisterType(type); + } } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs new file mode 100644 index 00000000..50b3d28b --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/CollectionNameProcessor.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Reflection; +using System.Text; +using MongoDB.Bson.Serialization; + +namespace MongoFramework.Infrastructure.Mapping.Processors +{ + public class CollectionNameProcessor : IMappingProcessor + { + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + { + var entityType = definition.EntityType; + var collectionName = entityType.Name; + + var tableAttribute = entityType.GetCustomAttribute(); + + if (tableAttribute == null && entityType.IsGenericType && entityType.GetGenericTypeDefinition() == typeof(EntityBucket<,>)) + { + var groupProperty = entityType.GetProperty("Group", BindingFlags.Public | BindingFlags.Instance); + tableAttribute = groupProperty.GetCustomAttribute(); + if (tableAttribute == null) + { + collectionName = groupProperty.PropertyType.Name; + } + } + + if (tableAttribute != null) + { + if (string.IsNullOrEmpty(tableAttribute.Schema)) + { + collectionName = tableAttribute.Name; + } + else + { + collectionName = tableAttribute.Schema + "." + tableAttribute.Name; + } + } + + definition.CollectionName = collectionName; + } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs index 9404643e..8e0800ba 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityIdProcessor.cs @@ -10,8 +10,10 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class EntityIdProcessor : IMappingProcessor { - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { + var entityType = definition.EntityType; + //If no Id member map exists, find the first property with the "Key" attribute or is named "Id" and use that if (classMap.IdMemberMap == null) { @@ -22,7 +24,7 @@ public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnect classMap.MapIdMember(idProperty); } } - + //If there is no Id generator, set a default based on the member type if (classMap.IdMemberMap != null && classMap.IdMemberMap.IdGenerator == null) { diff --git a/src/MongoFramework/Infrastructure/EntityRelationships/EntityMapperExtensions.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityRelationshipProcessor.cs similarity index 50% rename from src/MongoFramework/Infrastructure/EntityRelationships/EntityMapperExtensions.cs rename to src/MongoFramework/Infrastructure/Mapping/Processors/EntityRelationshipProcessor.cs index 073586b9..8f56cd5f 100644 --- a/src/MongoFramework/Infrastructure/EntityRelationships/EntityMapperExtensions.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityRelationshipProcessor.cs @@ -1,35 +1,56 @@ using MongoDB.Bson; -using MongoFramework.Infrastructure.Mapping; +using MongoDB.Bson.Serialization; +using MongoFramework.Infrastructure.Serialization; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Reflection; -namespace MongoFramework.Infrastructure.EntityRelationships +namespace MongoFramework.Infrastructure.Mapping.Processors { - public static class EntityMapperExtensions + public class EntityRelationshipProcessor : IMappingProcessor { public static readonly Type[] IdTypes = new[] { typeof(string), typeof(Guid), typeof(ObjectId) }; + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + { + definition.Relationships = GetEntityRelationships(definition).ToArray(); - public static IEnumerable GetEntityRelationships(this IEntityMapper entityMapper, IEntityMapperFactory entityMapperFactory) + foreach (var relationship in definition.Relationships) + { + if (relationship.IsCollection) + { + var memberMap = classMap.MapMember(relationship.NavigationProperty.PropertyInfo); + var serializerType = typeof(EntityNavigationCollectionSerializer<>).MakeGenericType(relationship.NavigationProperty.EntityType); + var collectionSerializer = Activator.CreateInstance(serializerType, relationship.IdProperty) as IBsonSerializer; + memberMap.SetSerializer(collectionSerializer); + } + else + { + classMap.UnmapMember(relationship.NavigationProperty.PropertyInfo); + } + } + } + private IEnumerable GetEntityRelationships(IEntityDefinition definition) { - var entityType = entityMapper.EntityType; - var propertyMap = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).ToDictionary(p => p.Name); + var entityType = definition.EntityType; + var propertyMap = definition.GetAllProperties().ToDictionary(p => p.PropertyInfo.Name, p => p); foreach (var mapping in propertyMap) { var currentProperty = mapping.Value; + var propertyInfo = currentProperty.PropertyInfo; + var propertyType = currentProperty.PropertyType; //For a single entity relationship - var foreignKeyAttr = currentProperty.GetCustomAttribute(); + var foreignKeyAttr = propertyInfo.GetCustomAttribute(); if (foreignKeyAttr != null) { var linkedProperty = propertyMap.ContainsKey(foreignKeyAttr.Name) ? propertyMap[foreignKeyAttr.Name] : null; if (linkedProperty == null) { - throw new InvalidOperationException($"Can't find property {foreignKeyAttr.Name} in {entityType.Name} as indicated by the ForeignKeyAttribute."); + throw new InvalidOperationException($"Can't find property {foreignKeyAttr.Name} in {entityType.Name} as indicated by the {nameof(ForeignKeyAttribute)}."); } else if (IdTypes.Contains(currentProperty.PropertyType)) { @@ -51,29 +72,28 @@ public static IEnumerable GetEntityRelationships(this IEntit } else { - throw new InvalidOperationException($"Unable to determine the Id property between {currentProperty.Name} and {linkedProperty.Name}. Check the types for these properties are correct."); + throw new InvalidOperationException($"Unable to determine the Id property between {currentProperty} and {linkedProperty}. Check the types for these properties are valid."); } continue; } //For an entity collection relationship - var propertyType = currentProperty.PropertyType; - if (currentProperty.CanRead && currentProperty.GetGetMethod().IsVirtual && propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(ICollection<>)) + if (propertyInfo.CanRead && propertyInfo.GetGetMethod().IsVirtual && propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(ICollection<>)) { var collectionEntityType = propertyType.GetGenericArguments().FirstOrDefault(); - var inversePropertyAttr = currentProperty.GetCustomAttribute(); - var relatedEntityMapping = entityMapperFactory.GetEntityMapper(collectionEntityType).GetEntityMapping(); + var inversePropertyAttr = propertyInfo.GetCustomAttribute(); + var relatedEntityMapping = EntityMapping.GetOrCreateDefinition(collectionEntityType).GetAllProperties(); - PropertyInfo idProperty; + IEntityProperty idProperty; if (inversePropertyAttr != null) { - idProperty = relatedEntityMapping.Where(m => m.Property.Name == inversePropertyAttr.Property).Select(m => m.Property).FirstOrDefault(); + idProperty = relatedEntityMapping.Where(p => p.PropertyInfo.Name == inversePropertyAttr.Property).FirstOrDefault(); if (idProperty == null) { - throw new InvalidOperationException($"Can't find property {inversePropertyAttr.Property} in {collectionEntityType} as indicated by the InversePropertyAttribute on {currentProperty.Name} in {entityType}"); + throw new InvalidOperationException($"Can't find property {inversePropertyAttr.Property} in {collectionEntityType} as indicated by the InversePropertyAttribute on {currentProperty}"); } else if (!IdTypes.Contains(idProperty.PropertyType)) { @@ -83,7 +103,7 @@ public static IEnumerable GetEntityRelationships(this IEntit else { //Default to the Id when no specific foreign key is found - idProperty = relatedEntityMapping.Where(m => m.IsKey).Select(m => m.Property).FirstOrDefault(); + idProperty = relatedEntityMapping.Where(p => p.IsKey).FirstOrDefault(); } yield return new EntityRelationship diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs index 3a224e3a..91ef0d57 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/ExtraElementsProcessor.cs @@ -9,8 +9,10 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class ExtraElementsProcessor : IMappingProcessor { - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { + var entityType = definition.EntityType; + //Ignore extra elements when the "IgnoreExtraElementsAttribute" is on the Entity var ignoreExtraElements = entityType.GetCustomAttribute(); if (ignoreExtraElements != null) diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs index 923a8631..329c6122 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs @@ -5,11 +5,12 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class HierarchyProcessor : IMappingProcessor { - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { - if (entityType != typeof(object) && entityType.BaseType != typeof(object)) + var entityType = definition.EntityType; + if (entityType != typeof(object) && entityType != typeof(object)) { - connection.GetEntityMapper(entityType.BaseType); + EntityMapping.RegisterType(entityType.BaseType); } else { diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs new file mode 100644 index 00000000..86c56327 --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using MongoDB.Bson.Serialization; +using MongoFramework.Attributes; + +namespace MongoFramework.Infrastructure.Mapping.Processors +{ + public class IndexProcessor : IMappingProcessor + { + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + { + definition.Indexes = definition.TraverseProperties().SelectMany(p => + p.PropertyInfo.GetCustomAttributes().Select(a => new EntityIndex + { + Property = p, + IndexName = a.Name, + IsUnique = a.IsUnique, + SortOrder = a.SortOrder + }) + ); + } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/MappedPropertiesProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/MappedPropertiesProcessor.cs index 7cbe3ef4..f97172c0 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/MappedPropertiesProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/MappedPropertiesProcessor.cs @@ -7,8 +7,9 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class MappedPropertiesProcessor : IMappingProcessor { - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { + var entityType = definition.EntityType; var properties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var property in properties) diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/NavigationPropertyProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/NavigationPropertyProcessor.cs deleted file mode 100644 index e4da4502..00000000 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/NavigationPropertyProcessor.cs +++ /dev/null @@ -1,30 +0,0 @@ -using MongoDB.Bson.Serialization; -using MongoFramework.Infrastructure.EntityRelationships; -using System; - -namespace MongoFramework.Infrastructure.Mapping.Processors -{ - public class NavigationPropertyProcessor : IMappingProcessor - { - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) - { - var entityMapper = connection.GetEntityMapper(entityType); - var relationships = entityMapper.GetEntityRelationships(connection); - - foreach (var relationship in relationships) - { - if (relationship.IsCollection) - { - var memberMap = classMap.MapMember(relationship.NavigationProperty); - var serializerType = typeof(EntityNavigationCollectionSerializer<>).MakeGenericType(relationship.EntityType); - var collectionSerializer = Activator.CreateInstance(serializerType, relationship.IdProperty.Name, connection) as IBsonSerializer; - memberMap.SetSerializer(collectionSerializer); - } - else - { - classMap.UnmapMember(relationship.NavigationProperty); - } - } - } - } -} diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedPropertyProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedPropertyProcessor.cs index 3cee48f1..815d5b07 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedPropertyProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedPropertyProcessor.cs @@ -8,8 +8,9 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { public class NestedPropertyProcessor : IMappingProcessor { - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { + var entityType = definition.EntityType; var properties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var property in properties) @@ -19,7 +20,10 @@ public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnect //Maps the property type for handling property nesting if (propertyType.IsClass && propertyType != entityType) { - connection.GetEntityMapper(propertyType); + if (!EntityMapping.IsRegistered(propertyType)) + { + EntityMapping.RegisterType(propertyType); + } } else if ( propertyType.IsGenericType && propertyType.GetGenericArguments().Count() == 1 && @@ -29,7 +33,11 @@ public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnect ) ) { - connection.GetEntityMapper(propertyType.GetGenericArguments()[0]); + var genericType = propertyType.GetGenericArguments()[0]; + if (!EntityMapping.IsRegistered(genericType)) + { + EntityMapping.RegisterType(genericType); + } } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertiesProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertiesProcessor.cs new file mode 100644 index 00000000..6247830c --- /dev/null +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/PropertiesProcessor.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using MongoDB.Bson.Serialization; + +namespace MongoFramework.Infrastructure.Mapping.Processors +{ + public class PropertiesProcessor : IMappingProcessor + { + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) + { + definition.Properties = classMap.DeclaredMemberMaps.Select(m => new EntityProperty + { + EntityType = definition.EntityType, + IsKey = m == classMap.IdMemberMap, + ElementName = m.ElementName, + FullPath = m.ElementName, + PropertyType = (m.MemberInfo as PropertyInfo).PropertyType, + PropertyInfo = m.MemberInfo as PropertyInfo + }); + } + } +} diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs index c7d5011f..1fbb3e12 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/TypeDiscoveryProcessor.cs @@ -2,7 +2,7 @@ using MongoDB.Bson.Serialization; using System.Reflection; using MongoFramework.Attributes; -using MongoFramework.Infrastructure.Mapping.Serialization; +using MongoFramework.Infrastructure.Serialization; namespace MongoFramework.Infrastructure.Mapping.Processors { @@ -10,15 +10,14 @@ public class TypeDiscoveryProcessor : IMappingProcessor { private static bool ProviderAdded { get; set; } - public void ApplyMapping(Type entityType, BsonClassMap classMap, IMongoDbConnection connection) + public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { + var entityType = definition.EntityType; if (!ProviderAdded && entityType.GetCustomAttribute() != null) { ProviderAdded = true; BsonSerializer.RegisterSerializationProvider(TypeDiscoverySerializationProvider.Instance); } - - TypeDiscoverySerializationProvider.Instance.AddMapping(entityType, connection); } } } diff --git a/src/MongoFramework/Infrastructure/Mutation/Mutators/EntityAttributeMutator.cs b/src/MongoFramework/Infrastructure/Mutation/Mutators/EntityAttributeMutator.cs index 88060991..d4aa5442 100644 --- a/src/MongoFramework/Infrastructure/Mutation/Mutators/EntityAttributeMutator.cs +++ b/src/MongoFramework/Infrastructure/Mutation/Mutators/EntityAttributeMutator.cs @@ -1,4 +1,5 @@ using MongoFramework.Attributes; +using MongoFramework.Infrastructure.Mapping; using System.Linq; using System.Reflection; @@ -8,28 +9,28 @@ public class EntityAttributeMutator : IEntityMutator where TEn { public void MutateEntity(TEntity entity, MutatorType mutationType, IMongoDbConnection connection) { - var entityMapper = connection.GetEntityMapper(typeof(TEntity)); - var mutateProperties = entityMapper.GetEntityMapping().Select(m => new + var definition = EntityMapping.GetOrCreateDefinition(typeof(TEntity)); + var mutatePropertiesMap = definition.GetAllProperties().Select(p => new { - PropertyInfo = m.Property, - MutateAttribute = m.Property.GetCustomAttribute(true) + Property = p, + MutateAttribute = p.PropertyInfo.GetCustomAttribute(true) }).Where(p => p.MutateAttribute != null).ToArray(); - foreach (var property in mutateProperties) + foreach (var propertyMap in mutatePropertiesMap) { if (mutationType == MutatorType.Insert) { - property.MutateAttribute.OnInsert(entity, property.PropertyInfo); + propertyMap.MutateAttribute.OnInsert(entity, propertyMap.Property); } if (mutationType == MutatorType.Update) { - property.MutateAttribute.OnUpdate(entity, property.PropertyInfo); + propertyMap.MutateAttribute.OnUpdate(entity, propertyMap.Property); } if (mutationType == MutatorType.Select) { - property.MutateAttribute.OnSelect(entity, property.PropertyInfo); + propertyMap.MutateAttribute.OnSelect(entity, propertyMap.Property); } } } diff --git a/src/MongoFramework/Infrastructure/Mutation/Mutators/NavigationPropertyMutator.cs b/src/MongoFramework/Infrastructure/Mutation/Mutators/NavigationPropertyMutator.cs index ceb1bb67..e41f62e3 100644 --- a/src/MongoFramework/Infrastructure/Mutation/Mutators/NavigationPropertyMutator.cs +++ b/src/MongoFramework/Infrastructure/Mutation/Mutators/NavigationPropertyMutator.cs @@ -1,4 +1,4 @@ -using MongoFramework.Infrastructure.EntityRelationships; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Linq; using System; using System.Linq; @@ -10,7 +10,7 @@ public class NavigationPropertyMutator : IEntityMutator where { public void MutateEntity(TEntity entity, MutatorType mutationType, IMongoDbConnection connection) { - var relationships = connection.GetEntityMapper(typeof(TEntity)).GetEntityRelationships(connection); + var relationships = EntityMapping.GetOrCreateDefinition(typeof(TEntity)).Relationships; foreach (var relationship in relationships) { if (mutationType == MutatorType.Select && !relationship.IsCollection) @@ -21,14 +21,22 @@ public void MutateEntity(TEntity entity, MutatorType mutationType, IMongoDbConne else if (mutationType == MutatorType.Create && relationship.IsCollection) { var navigationCollectionType = typeof(EntityNavigationCollection<>).MakeGenericType(relationship.EntityType); - var navigationCollection = Activator.CreateInstance(navigationCollectionType, relationship.IdProperty.Name, connection) as IEntityNavigationCollection; + var navigationCollection = Activator.CreateInstance(navigationCollectionType, relationship.IdProperty) as IEntityNavigationCollection; + navigationCollection.SetConnection(connection); relationship.NavigationProperty.SetValue(entity, navigationCollection); } + else if (mutationType == MutatorType.Select && relationship.IsCollection) + { + if (relationship.NavigationProperty.GetValue(entity) is IEntityNavigationCollection navigationCollection) + { + navigationCollection.SetConnection(connection); + } + } } } #pragma warning disable CRR0026 // Unused member - called through Reflection - private static void InitialiseSingleEntityRelationship(TEntity targetEntity, EntityRelationship relationship, IMongoDbConnection connection) where TRelatedEntity : class + private static void InitialiseSingleEntityRelationship(TEntity targetEntity, IEntityRelationship relationship, IMongoDbConnection connection) where TRelatedEntity : class { var dbEntityReader = new EntityReader(connection); var relationshipIdValue = relationship.IdProperty.GetValue(targetEntity); diff --git a/src/MongoFramework/Infrastructure/EntityRelationships/EntityNavigationCollectionSerializer.cs b/src/MongoFramework/Infrastructure/Serialization/EntityNavigationCollectionSerializer.cs similarity index 79% rename from src/MongoFramework/Infrastructure/EntityRelationships/EntityNavigationCollectionSerializer.cs rename to src/MongoFramework/Infrastructure/Serialization/EntityNavigationCollectionSerializer.cs index e157e821..0d5791cc 100644 --- a/src/MongoFramework/Infrastructure/EntityRelationships/EntityNavigationCollectionSerializer.cs +++ b/src/MongoFramework/Infrastructure/Serialization/EntityNavigationCollectionSerializer.cs @@ -5,23 +5,16 @@ using System.Collections.Generic; using System.Linq; -namespace MongoFramework.Infrastructure.EntityRelationships +namespace MongoFramework.Infrastructure.Serialization { public class EntityNavigationCollectionSerializer : IBsonSerializer>, IBsonArraySerializer where TEntity : class { - private IMongoDbConnection Connection { get; } - private IEntityPropertyMap ForeignPropertyMap { get; } - - public string ForeignKey { get; } + public IEntityProperty ForeignProperty { get; } public Type ValueType => typeof(ICollection); - public EntityNavigationCollectionSerializer(string foreignKey, IMongoDbConnection connection) + public EntityNavigationCollectionSerializer(IEntityProperty foreignProperty) { - ForeignKey = foreignKey; - Connection = connection; - - var entityMapper = Connection.GetEntityMapper(typeof(TEntity)); - ForeignPropertyMap = entityMapper.GetEntityMapping().Where(m => m.Property.Name == foreignKey).FirstOrDefault(); + ForeignProperty = foreignProperty; } public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) @@ -29,7 +22,7 @@ public object Deserialize(BsonDeserializationContext context, BsonDeserializatio var type = context.Reader.GetCurrentBsonType(); if (type == BsonType.Array) { - var collection = new EntityNavigationCollection(ForeignKey, Connection); + var collection = new EntityNavigationCollection(ForeignProperty); context.Reader.ReadStartArray(); while (context.Reader.ReadBsonType() != BsonType.EndOfDocument) @@ -56,7 +49,7 @@ public object Deserialize(BsonDeserializationContext context, BsonDeserializatio else if (type == BsonType.Null) { context.Reader.ReadNull(); - return new EntityNavigationCollection(ForeignKey, Connection); + return new EntityNavigationCollection(ForeignProperty); } else { @@ -80,7 +73,7 @@ public void Serialize(BsonSerializationContext context, BsonSerializationArgs ar } else if (value is ICollection simpleCollection) { - foreignIds = simpleCollection.Select(e => ForeignPropertyMap.Property.GetValue(e)); + foreignIds = simpleCollection.Select(e => ForeignProperty.PropertyInfo.GetValue(e)); } else { @@ -115,8 +108,8 @@ public void Serialize(BsonSerializationContext context, BsonSerializationArgs ar public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo) { - var serializer = BsonSerializer.LookupSerializer(ForeignPropertyMap.PropertyType); - serializationInfo = new BsonSerializationInfo(null, serializer, ForeignPropertyMap.PropertyType); + var serializer = BsonSerializer.LookupSerializer(ForeignProperty.PropertyType); + serializationInfo = new BsonSerializationInfo(null, serializer, ForeignProperty.PropertyType); return true; } diff --git a/src/MongoFramework/Infrastructure/Mapping/Serialization/TypeDiscoverySerializationProvider.cs b/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializationProvider.cs similarity index 64% rename from src/MongoFramework/Infrastructure/Mapping/Serialization/TypeDiscoverySerializationProvider.cs rename to src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializationProvider.cs index 083bf5a6..fd61e536 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Serialization/TypeDiscoverySerializationProvider.cs +++ b/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializationProvider.cs @@ -4,7 +4,7 @@ using MongoDB.Bson.Serialization; using MongoFramework.Attributes; -namespace MongoFramework.Infrastructure.Mapping.Serialization +namespace MongoFramework.Infrastructure.Serialization { public class TypeDiscoverySerializationProvider : BsonSerializationProviderBase { @@ -12,8 +12,6 @@ public class TypeDiscoverySerializationProvider : BsonSerializationProviderBase public bool Enabled { get; set; } = true; - private Dictionary EntityFactoryMapping { get; } = new Dictionary(); - public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry) { if (type == null) @@ -23,20 +21,11 @@ public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry if (Enabled && type.GetCustomAttribute() != null) { - var entityMapperFactory = EntityFactoryMapping[type]; var serializerType = typeof(TypeDiscoverySerializer<>).MakeGenericType(type); - return (IBsonSerializer)Activator.CreateInstance(serializerType, entityMapperFactory); + return (IBsonSerializer)Activator.CreateInstance(serializerType); } return null; } - - public void AddMapping(Type type, IEntityMapperFactory mapperFactory) - { - if (!EntityFactoryMapping.ContainsKey(type)) - { - EntityFactoryMapping.Add(type, mapperFactory); - } - } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/Serialization/TypeDiscoverySerializer.cs b/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializer.cs similarity index 93% rename from src/MongoFramework/Infrastructure/Mapping/Serialization/TypeDiscoverySerializer.cs rename to src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializer.cs index d0ab923e..48b05dcd 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Serialization/TypeDiscoverySerializer.cs +++ b/src/MongoFramework/Infrastructure/Serialization/TypeDiscoverySerializer.cs @@ -6,22 +6,17 @@ using System.Collections.Concurrent; using System.Linq; using System.Threading; +using MongoFramework.Infrastructure.Mapping; -namespace MongoFramework.Infrastructure.Mapping.Serialization +namespace MongoFramework.Infrastructure.Serialization { public class TypeDiscoverySerializer : IBsonSerializer, IBsonDocumentSerializer, IBsonIdProvider where TEntity : class { private static ReaderWriterLockSlim TypeCacheLock { get; } = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); private static ConcurrentBag AssignableTypes { get; } = new ConcurrentBag(); - private IEntityMapperFactory EntityMapperFactory { get; } public Type ValueType => typeof(TEntity); - public TypeDiscoverySerializer(IEntityMapperFactory entityMapperFactory) - { - EntityMapperFactory = entityMapperFactory; - } - public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var type = context.Reader.GetCurrentBsonType(); @@ -100,7 +95,10 @@ private Type FindTypeByName(string name) private IBsonSerializer GetRealSerializer(Type type) { //Force the type to be processed by the Entity Mapper - EntityMapperFactory.GetEntityMapper(type); + if (!EntityMapping.IsRegistered(type)) + { + EntityMapping.RegisterType(type); + } var classMap = BsonClassMap.LookupClassMap(type); var serializerType = typeof(BsonClassMapSerializer<>).MakeGenericType(type); diff --git a/src/MongoFramework/Linq/LinqExtensions.cs b/src/MongoFramework/Linq/LinqExtensions.cs index 39179dd2..97d9ac69 100644 --- a/src/MongoFramework/Linq/LinqExtensions.cs +++ b/src/MongoFramework/Linq/LinqExtensions.cs @@ -1,4 +1,5 @@ using MongoFramework.Infrastructure.Linq; +using MongoFramework.Infrastructure.Mapping; using System; using System.Collections; using System.Linq; @@ -21,29 +22,26 @@ public static string ToQuery(this IQueryable queryable) public static IQueryable WhereIdMatches(this IQueryable queryable, IEnumerable entityIds) where TEntity : class { - if (queryable is IMongoFrameworkQueryable mongoDbQueryable) - { - var entityMapper = mongoDbQueryable.Connection.GetEntityMapper(typeof(TEntity)); - var idProperty = entityMapper.GetEntityMapping().Where(m => m.IsKey).Select(m => m.Property).FirstOrDefault(); - return queryable.WherePropertyMatches(idProperty.Name, idProperty.PropertyType, entityIds); - } + var idProperty = EntityMapping.GetOrCreateDefinition(typeof(TEntity)) + .GetAllProperties() + .Where(p => p.IsKey) + .FirstOrDefault(); - //TODO: Look at potentially avoiding the EntityMapper by looking at the BsonClassMapSerializer instead? - throw new ArgumentException($"Queryable must implement interface {nameof(IMongoFrameworkQueryable)}", nameof(queryable)); + return queryable.WherePropertyMatches(idProperty, entityIds); } - public static IQueryable WherePropertyMatches(this IQueryable queryable, string propertyName, Type propertyType, IEnumerable identifiers) where TEntity : class + public static IQueryable WherePropertyMatches(this IQueryable queryable, IEntityProperty property, IEnumerable values) where TEntity : class { - //The cast allows for handling identifiers generically as "IEnumerable". Without the Cast call, we can't handle ObjectId identifiers. + //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(propertyType).Invoke(null, new[] { identifiers }); + var castedIdentifiers = castMethod.MakeGenericMethod(property.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, propertyName); + var propertyExpression = Expression.Property(entityParameter, property.PropertyInfo.Name); var identifiersExpression = Expression.Constant(castedIdentifiers); var expression = Expression.Lambda>( - Expression.Call(typeof(Enumerable), "Contains", new[] { propertyType }, identifiersExpression, propertyExpression), + Expression.Call(typeof(Enumerable), "Contains", new[] { property.PropertyType }, identifiersExpression, propertyExpression), entityParameter ); diff --git a/src/MongoFramework/MongoDbBucketSet.cs b/src/MongoFramework/MongoDbBucketSet.cs index 6c2dee13..7d0d49c5 100644 --- a/src/MongoFramework/MongoDbBucketSet.cs +++ b/src/MongoFramework/MongoDbBucketSet.cs @@ -44,10 +44,8 @@ public void SetConnection(IMongoDbConnection connection) EntityWriter = new EntityWriter>(connection); EntityReader = new EntityReader>(connection); EntityIndexWriter = new EntityIndexWriter>(connection); - - var entityMapper = connection.GetEntityMapper(typeof(EntityBucket)); - BucketCollection = new EntityBucketCollection(EntityReader, BucketSize, entityMapper); - ChangeTracker = new EntityChangeTracker>(entityMapper); + BucketCollection = new EntityBucketCollection(EntityReader, BucketSize); + ChangeTracker = new EntityChangeTracker>(); } public virtual void Add(TGroup group, TSubEntity entity) diff --git a/src/MongoFramework/MongoDbConnection.cs b/src/MongoFramework/MongoDbConnection.cs index 5fc6c2b1..59bf4036 100644 --- a/src/MongoFramework/MongoDbConnection.cs +++ b/src/MongoFramework/MongoDbConnection.cs @@ -2,8 +2,7 @@ using System.Collections.Concurrent; using MongoDB.Driver; using MongoFramework.Infrastructure; -using MongoFramework.Infrastructure.Indexing; -using MongoFramework.Infrastructure.Mapping; +using MongoFramework.Infrastructure.Diagnostics; namespace MongoFramework { @@ -31,8 +30,6 @@ public IMongoClient Client } } - private ConcurrentDictionary EntityMapperCache { get; } = new ConcurrentDictionary(); - public IDiagnosticListener DiagnosticListener { get; set; } = new NoOpDiagnosticListener(); public static MongoDbConnection FromUrl(MongoUrl mongoUrl) @@ -48,14 +45,9 @@ public static MongoDbConnection FromUrl(MongoUrl mongoUrl) }; } - public static MongoDbConnection FromConnectionString(string connectionString, string databaseName) + public static MongoDbConnection FromConnectionString(string connectionString) { - var urlBuilder = new MongoUrlBuilder(connectionString) - { - DatabaseName = databaseName - }; - - return FromUrl(urlBuilder.ToMongoUrl()); + return FromUrl(new MongoUrl(connectionString)); } #if !NETCOREAPP2_0 @@ -83,30 +75,6 @@ public IMongoDatabase GetDatabase() return Client.GetDatabase(Url.DatabaseName); } - public IEntityMapper GetEntityMapper(Type entityType) - { - if (IsDisposed) - { - throw new ObjectDisposedException(nameof(MongoDbConnection)); - } - - return EntityMapperCache.GetOrAdd(entityType, (type) => - { - return new EntityMapper(type, this); - }); - } - - public IEntityIndexMapper GetIndexMapper(Type entityType) - { - if (IsDisposed) - { - throw new ObjectDisposedException(nameof(MongoDbConnection)); - } - - var entityMapper = GetEntityMapper(entityType); - return new EntityIndexMapper(entityMapper); - } - public void Dispose() { Dispose(true); diff --git a/src/MongoFramework/MongoDbSet.cs b/src/MongoFramework/MongoDbSet.cs index 2d4a2e55..a4f0a30d 100644 --- a/src/MongoFramework/MongoDbSet.cs +++ b/src/MongoFramework/MongoDbSet.cs @@ -1,5 +1,4 @@ using MongoFramework.Infrastructure; -using MongoFramework.Infrastructure.EntityRelationships; using MongoFramework.Infrastructure.Indexing; using MongoFramework.Infrastructure.Linq; using MongoFramework.Infrastructure.Linq.Processors; @@ -47,7 +46,7 @@ public void SetConnection(IMongoDbConnection connection) EntityReader = new EntityReader(connection); EntityIndexWriter = new EntityIndexWriter(connection); EntityRelationshipWriter = new EntityRelationshipWriter(connection); - ChangeTracker = new EntityChangeTracker(connection.GetEntityMapper(typeof(TEntity))); + ChangeTracker = new EntityChangeTracker(); } public virtual TEntity Create() diff --git a/src/MongoFramework/Infrastructure/MongoDbUtility.cs b/src/MongoFramework/MongoDbUtility.cs similarity index 90% rename from src/MongoFramework/Infrastructure/MongoDbUtility.cs rename to src/MongoFramework/MongoDbUtility.cs index f8a4e86f..d9d90df5 100644 --- a/src/MongoFramework/Infrastructure/MongoDbUtility.cs +++ b/src/MongoFramework/MongoDbUtility.cs @@ -1,6 +1,6 @@ using MongoDB.Bson; -namespace MongoFramework.Infrastructure +namespace MongoFramework { public static class MongoDbUtility { diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityChangeTrackerTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityChangeTrackerTests.cs index d4d83178..4af6a5f6 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityChangeTrackerTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityChangeTrackerTests.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoFramework.Infrastructure; -using MongoFramework.Infrastructure.Mapping; using System.Linq; namespace MongoFramework.Tests.Infrastructure @@ -17,8 +16,7 @@ public class ChangeTrackerModel [TestMethod] public void DetectChangesDoesntCountAddedEntries() { - var entityMapper = new EntityMapper(TestConfiguration.GetConnection()); - var changeTracker = new EntityChangeTracker(entityMapper); + var changeTracker = new EntityChangeTracker(); var entity = new ChangeTrackerModel { Title = "DbChangeTrackerTests.DetectChangesWhenNoneExist" @@ -33,8 +31,7 @@ public void DetectChangesDoesntCountAddedEntries() [TestMethod] public void DetectAnyChanges() { - var entityMapper = new EntityMapper(TestConfiguration.GetConnection()); - var changeTracker = new EntityChangeTracker(entityMapper); + var changeTracker = new EntityChangeTracker(); var entity = new ChangeTrackerModel { Title = "DbChangeTrackerTests.DetectAnyChanges" @@ -51,8 +48,7 @@ public void DetectAnyChanges() [TestMethod] public void DetectAnyChangesThenChangedBackToOriginal() { - var entityMapper = new EntityMapper(TestConfiguration.GetConnection()); - var changeTracker = new EntityChangeTracker(entityMapper); + var changeTracker = new EntityChangeTracker(); var entity = new ChangeTrackerModel { Title = "DbChangeTrackerTests.DetectAnyChangesThenChangedBackToOriginal" @@ -73,8 +69,7 @@ public void DetectAnyChangesThenChangedBackToOriginal() [TestMethod] public void CommittedChangesAreUpdated() { - var entityMapper = new EntityMapper(TestConfiguration.GetConnection()); - var changeTracker = new EntityChangeTracker(entityMapper); + var changeTracker = new EntityChangeTracker(); var addedEntity = new ChangeTrackerModel(); var updatedEntity = new ChangeTrackerModel(); diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityCollectionTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityCollectionTests.cs index 2ea0770a..23ba9269 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityCollectionTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityCollectionTests.cs @@ -17,8 +17,7 @@ public class EntityCollectionModel [TestMethod] public void AddNewEntry() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var entity = new EntityCollectionModel { Title = "DbEntityCollectionTests.AddNewEntry" @@ -31,8 +30,7 @@ public void AddNewEntry() [TestMethod] public void UpdateExistingEntryIdMatch() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var entity = new EntityCollectionModel { Id = "123", @@ -55,8 +53,7 @@ public void UpdateExistingEntryIdMatch() [TestMethod] public void UpdateExistingEntryInstanceMatch() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var entity = new EntityCollectionModel { Title = "DbEntityCollectionTests.UpdateExistingEntryWithoutId" @@ -71,8 +68,7 @@ public void UpdateExistingEntryInstanceMatch() [TestMethod] public void RemoveRange() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var entities = new[] { new EntityCollectionModel @@ -102,8 +98,7 @@ public void RemoveRange() [TestMethod] public void ClearTracker() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var entity = new EntityCollectionModel { Title = "DbEntityCollectionTests.ClearTracker" @@ -118,16 +113,14 @@ public void ClearTracker() [TestMethod] public void RemoveNonExistentEntities() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); Assert.IsFalse(entityCollection.Remove(new EntityCollectionModel { })); } [TestMethod] public void ContainsExactEntity() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var entity = new EntityCollectionModel { Id = "ABC" @@ -140,8 +133,7 @@ public void ContainsExactEntity() [TestMethod] public void ContainsEntityById() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var entity = new EntityCollectionModel { Id = "ABC", @@ -161,8 +153,7 @@ public void ContainsEntityById() [ExpectedException(typeof(ArgumentNullException))] public void CopyToInvalidArray() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); EntityCollectionModel[] array = null; entityCollection.CopyTo(array, 0); } @@ -171,8 +162,7 @@ public void CopyToInvalidArray() [ExpectedException(typeof(IndexOutOfRangeException))] public void CopyToIndexOutOfRangeLow() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))); + var entityCollection = new EntityCollection(); var array = new EntityCollectionModel[4]; entityCollection.CopyTo(array, -1); } @@ -181,8 +171,7 @@ public void CopyToIndexOutOfRangeLow() [ExpectedException(typeof(IndexOutOfRangeException))] public void CopyToIndexOutOfRangeHigh() { - var connection = TestConfiguration.GetConnection(); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(EntityCollectionModel))) + var entityCollection = new EntityCollection() { new EntityCollectionModel { }, new EntityCollectionModel { }, diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityReaderTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityReaderTests.cs index 9edfea41..0fd7b676 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityReaderTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityReaderTests.cs @@ -21,7 +21,7 @@ public class B : A public void ReadMixedEntities() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(A))); + var entityContainer = new EntityCollection(); var reader = new EntityReader(connection); var writer = new EntityWriter(connection); diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/CollectionMappingTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/CollectionMappingTests.cs deleted file mode 100644 index 8128134f..00000000 --- a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/CollectionMappingTests.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MongoFramework.Infrastructure.EntityRelationships; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; - -namespace MongoFramework.Tests.Infrastructure.EntityRelationships -{ - [TestClass] - public class CollectionMappingTests : TestBase - { - public class CollectionMappingModel - { - public string Id { get; set; } - public string Description { get; set; } - - public virtual ICollection StringModelEntities { get; set; } - public virtual ICollection ObjectIdModelEntities { get; set; } - public virtual ICollection GuidModelEntities { get; set; } - - [InverseProperty("SecondaryId")] - public virtual ICollection InverseCollection { get; set; } - } - - public class InversePropertyMappingInvalidPropertyTypeModel - { - public string Id { get; set; } - - [InverseProperty("CreatedDate")] - public virtual ICollection StringModelEntities { get; set; } - } - - public class InversePropertyNonExistantPropertyModel - { - public string Id { get; set; } - - [InverseProperty("NonExistantPropertyId")] - public virtual ICollection StringModelEntities { get; set; } - } - - public class ValidInversePropertyModel - { - public string Id { get; set; } - - [InverseProperty("SecondaryId")] - public virtual ICollection StringModelEntities { get; set; } - } - - [TestMethod] - public void IdentifyCollectionRelationships() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(CollectionMappingModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection); - - Assert.IsTrue(relationships.All(r => r.IsCollection)); - - var relationship = relationships.Where(r => r.NavigationProperty.Name == "StringModelEntities").FirstOrDefault(); - - Assert.IsTrue(relationship.IsCollection); - Assert.AreEqual(typeof(StringIdModel), relationship.EntityType); - Assert.AreEqual(typeof(StringIdModel).GetProperty("Id"), relationship.IdProperty); - Assert.AreEqual(typeof(CollectionMappingModel).GetProperty("StringModelEntities"), relationship.NavigationProperty); - } - - [TestMethod] - public void ValidInversePropertyMapping() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(ValidInversePropertyModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection); - - Assert.IsTrue(relationships.Any(r => r.IsCollection && r.IdProperty.Name == "SecondaryId")); - } - - [TestMethod] - [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+ in .+")] - public void InversePropertyMappingNonExistantProperty() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(InversePropertyNonExistantPropertyModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection); - } - - [TestMethod] - [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+ in .+")] - public void InversePropertyMappingInvalidPropertyType() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(InversePropertyMappingInvalidPropertyTypeModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection); - } - } -} diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionIntegrationTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionIntegrationTests.cs index 9c934bba..33220433 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionIntegrationTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionIntegrationTests.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson; -using MongoFramework.Infrastructure.EntityRelationships; +using MongoFramework.Infrastructure; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs index 0147f828..7c95187e 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson; -using MongoFramework.Infrastructure.EntityRelationships; +using MongoFramework.Infrastructure; +using MongoFramework.Infrastructure.Mapping; using System; namespace MongoFramework.Tests.Infrastructure.EntityRelationships @@ -11,29 +12,22 @@ public class EntityNavigationCollectionUnitTests : TestBase [TestMethod, ExpectedException(typeof(ArgumentNullException))] public void NullForeignKeyThrowsException() { - var connection = TestConfiguration.GetConnection(); - new EntityNavigationCollection(null, connection); - } - - [TestMethod, ExpectedException(typeof(ArgumentNullException))] - public void NullConnectionThrowsException() - { - new EntityNavigationCollection("Id", null); + new EntityNavigationCollection(null); } [TestMethod, ExpectedException(typeof(ArgumentNullException))] public void AddForeignIdWithNull() { - var connection = TestConfiguration.GetConnection(); - var collection = new EntityNavigationCollection("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var collection = new EntityNavigationCollection(foreignProperty); collection.AddForeignId(null); } [TestMethod] public void AddForeignIdWithRightType() { - var connection = TestConfiguration.GetConnection(); - var collection = new EntityNavigationCollection("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var collection = new EntityNavigationCollection(foreignProperty); collection.AddForeignId("12345678"); Assert.AreEqual(1, collection.UnloadedCount); } @@ -41,16 +35,16 @@ public void AddForeignIdWithRightType() [TestMethod, ExpectedException(typeof(InvalidOperationException))] public void AddForeignIdWithWrongType() { - var connection = TestConfiguration.GetConnection(); - var collection = new EntityNavigationCollection("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var collection = new EntityNavigationCollection(foreignProperty); collection.AddForeignId(ObjectId.GenerateNewId()); } [TestMethod] public void AddMultipleForeignIds() { - var connection = TestConfiguration.GetConnection(); - var collection = new EntityNavigationCollection("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var collection = new EntityNavigationCollection(foreignProperty); collection.AddForeignIds(new object[] { ObjectId.GenerateNewId(), ObjectId.GenerateNewId() }); Assert.AreEqual(2, collection.UnloadedCount); } diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityIntegrationTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityIntegrationTests.cs index dc6a0b2b..5bfefd52 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityIntegrationTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityIntegrationTests.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoFramework.Infrastructure; -using MongoFramework.Infrastructure.EntityRelationships; using MongoFramework.Infrastructure.Mutation; using MongoFramework.Infrastructure.Mutation.Mutators; using System.ComponentModel.DataAnnotations.Schema; @@ -70,7 +69,7 @@ public void LoadRelationship() Description = "LoadRelationship-RelatedItem" }; var dbEntityWriter = new EntityWriter(connection); - var collection = new EntityCollection(connection.GetEntityMapper(typeof(StringIdModel))) + var collection = new EntityCollection() { relatedEntity }; diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityMappingTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityMappingTests.cs deleted file mode 100644 index a80ae727..00000000 --- a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/SingleEntityMappingTests.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MongoDB.Bson; -using MongoFramework.Infrastructure.EntityRelationships; -using System; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; - -namespace MongoFramework.Tests.Infrastructure.EntityRelationships -{ - [TestClass] - public class SingleEntityMappingTests : TestBase - { - public class BaseEntityModel - { - public string Id { get; set; } - public string Description { get; set; } - - [ForeignKey("CreatedBy")] - public string CreatedById { get; set; } - public virtual UserEntityModel CreatedBy { get; set; } - - public string UpdatedById { get; set; } - [ForeignKey("UpdatedById")] - public virtual UserEntityModel UpdatedBy { get; set; } - } - - public class BaseVariedIdModel - { - public string Id { get; set; } - - [ForeignKey("GuidProperty")] - public Guid GuidTestId { get; set; } - public virtual GuidIdModel GuidProperty { get; set; } - - [ForeignKey("ObjectIdProperty")] - public ObjectId ObjectIdTestId { get; set; } - public virtual ObjectIdIdModel ObjectIdProperty { get; set; } - } - - public class InvalidForeignKeyModel - { - public string Id { get; set; } - - [ForeignKey("Created_By")] - public string CreatedById { get; set; } - public virtual UserEntityModel CreatedBy { get; set; } - } - - public class UnsupportedIdModel - { - public string Id { get; set; } - - [ForeignKey("CreatedBy")] - public int CreatedById { get; set; } - public virtual UserEntityModel CreatedBy { get; set; } - } - - public class UserEntityModel - { - public string Id { get; set; } - public string Username { get; set; } - } - - [TestMethod] - public void ForeignKeyAttributeOnId() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(BaseEntityModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection); - - var createdByIdProperty = typeof(BaseEntityModel).GetProperty("CreatedById"); - var attributeOnIdRelationship = relationships.Where(r => r.IdProperty == createdByIdProperty).FirstOrDefault(); - - Assert.IsFalse(attributeOnIdRelationship.IsCollection); - Assert.AreEqual(typeof(UserEntityModel), attributeOnIdRelationship.EntityType); - Assert.AreEqual(typeof(BaseEntityModel).GetProperty("CreatedBy"), attributeOnIdRelationship.NavigationProperty); - } - - [TestMethod] - public void ForeignKeyAttributeOnNavigationProperty() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(BaseEntityModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection); - - var updatedByIdProperty = typeof(BaseEntityModel).GetProperty("UpdatedById"); - var attributeOnIdRelationship = relationships.Where(r => r.IdProperty == updatedByIdProperty).FirstOrDefault(); - - Assert.IsFalse(attributeOnIdRelationship.IsCollection); - Assert.AreEqual(typeof(UserEntityModel), attributeOnIdRelationship.EntityType); - Assert.AreEqual(typeof(BaseEntityModel).GetProperty("UpdatedBy"), attributeOnIdRelationship.NavigationProperty); - } - - [TestMethod] - public void IdentifyRelationshipsWithOtherIdTypes() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(BaseVariedIdModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection); - Assert.AreEqual(2, relationships.Count()); - } - - [TestMethod] - [ExpectedExceptionPattern(typeof(InvalidOperationException), @"Unable to determine the Id property between .+ and .+\. Check the types for these properties are correct\.")] - public void UnsupportedIdTypeOnRelationship() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(UnsupportedIdModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection).ToArray(); - } - - [TestMethod] - [ExpectedExceptionPattern(typeof(InvalidOperationException), @"Can't find property .+ in .+ as indicated by the ForeignKeyAttribute.")] - public void InvalidForeignKeyOnRelationship() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(InvalidForeignKeyModel)); - var relationships = EntityMapperExtensions.GetEntityRelationships(entityMapper, connection).ToArray(); - } - - [TestMethod] - public void NavigationPropertiesUnmap() - { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(BaseEntityModel)); - Assert.IsFalse(entityMapper.GetEntityMapping().Any(e => e.FullPath == "CreatedBy" || e.FullPath == "UpdatedBy")); - } - } -} diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityWriterTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityWriterTests.cs index ae1425ca..fbae19d2 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityWriterTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityWriterTests.cs @@ -23,7 +23,7 @@ public class ExtendedEntityWriterModel : EntityWriterModel public void AddEntity() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(EntityWriterModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); var entity = new EntityWriterModel @@ -41,7 +41,7 @@ public void AddEntity() public void AddMixedTypeEntities() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(EntityWriterModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); var entities = new[] { @@ -71,7 +71,7 @@ public void AddMixedTypeEntities() public void UpdateEntity() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(EntityWriterModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); var reader = new EntityReader(connection); @@ -103,7 +103,7 @@ public void UpdateEntity() public void RemoveEntity() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(EntityWriterModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); var reader = new EntityReader(connection); @@ -128,7 +128,7 @@ public void RemoveEntity() public void MixedActionWrite() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(EntityWriterModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); var reader = new EntityReader(connection); @@ -166,7 +166,7 @@ public void MixedActionWrite() public async Task MixedActionWriteAsync() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(EntityWriterModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); var reader = new EntityReader(connection); diff --git a/tests/MongoFramework.Tests/Infrastructure/Indexing/EntityIndexMapperTests.cs b/tests/MongoFramework.Tests/Infrastructure/Indexing/EntityIndexMapperTests.cs deleted file mode 100644 index d2455fee..00000000 --- a/tests/MongoFramework.Tests/Infrastructure/Indexing/EntityIndexMapperTests.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MongoFramework.Infrastructure.Indexing; -using System; - -namespace MongoFramework.Tests.Infrastructure.Indexing -{ - [TestClass] - public class EntityIndexMapperTests : TestBase - { - public class SomeEntity { } - public class AnotherEntity { } - - [TestMethod, ExpectedException(typeof(InvalidOperationException))] - public void EntityTypeMismatchFromEntityMapper() - { - var connection = TestConfiguration.GetConnection(); - var indexMapper = new EntityIndexMapper(connection.GetEntityMapper(typeof(SomeEntity))); - } - } -} diff --git a/tests/MongoFramework.Tests/Infrastructure/Indexing/Processors/BasicIndexProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Indexing/IndexModelBuilderTests.cs similarity index 64% rename from tests/MongoFramework.Tests/Infrastructure/Indexing/Processors/BasicIndexProcessorTests.cs rename to tests/MongoFramework.Tests/Infrastructure/Indexing/IndexModelBuilderTests.cs index 7653e073..dd9de013 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Indexing/Processors/BasicIndexProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Indexing/IndexModelBuilderTests.cs @@ -1,13 +1,12 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoFramework.Attributes; using MongoFramework.Infrastructure.Indexing; -using MongoFramework.Infrastructure.Indexing.Processors; using System.Linq; namespace MongoFramework.Tests.Infrastructure.Indexing.Processors { [TestClass] - public class BasicIndexProcessorTests : TestBase + public class IndexModelBuilderTests : TestBase { public class IndexNamingModel { @@ -62,13 +61,8 @@ public class CompoundIndexModel [TestMethod] public void IndexNaming() { - var connection = TestConfiguration.GetConnection(); - var processor = new BasicIndexProcessor(); - var entityIndexMapper = new EntityIndexMapper(connection.GetEntityMapper(typeof(IndexNamingModel))); - var indexMapping = entityIndexMapper.GetIndexMapping(); - - var indexModel = processor.BuildIndexModel(indexMapping); - + var indexModel = IndexModelBuilder.BuildModel(); + Assert.AreEqual(2, indexModel.Count()); Assert.IsTrue(indexModel.Any(m => m.Options.Name == null)); Assert.IsTrue(indexModel.Any(m => m.Options.Name == "MyCustomIndexName")); @@ -77,12 +71,7 @@ public void IndexNaming() [TestMethod] public void AppliesIndexSortOrder() { - var connection = TestConfiguration.GetConnection(); - var processor = new BasicIndexProcessor(); - var entityIndexMapper = new EntityIndexMapper(connection.GetEntityMapper(typeof(IndexSortOrderModel))); - var indexMapping = entityIndexMapper.GetIndexMapping(); - - var indexModel = processor.BuildIndexModel(indexMapping); + var indexModel = IndexModelBuilder.BuildModel(); Assert.AreEqual(2, indexModel.Count()); @@ -94,12 +83,7 @@ public void AppliesIndexSortOrder() [TestMethod] public void AppliesUniqueConstraint() { - var connection = TestConfiguration.GetConnection(); - var processor = new BasicIndexProcessor(); - var entityIndexMapper = new EntityIndexMapper(connection.GetEntityMapper(typeof(UniqueConstraintModel))); - var indexMapping = entityIndexMapper.GetIndexMapping(); - - var indexModel = processor.BuildIndexModel(indexMapping); + var indexModel = IndexModelBuilder.BuildModel(); Assert.AreEqual(2, indexModel.Count()); Assert.IsTrue(indexModel.Any(m => m.Options.Name == "UniqueIndex" && m.Options.Unique == true)); @@ -109,12 +93,7 @@ public void AppliesUniqueConstraint() [TestMethod] public void CompoundIndex() { - var connection = TestConfiguration.GetConnection(); - var processor = new BasicIndexProcessor(); - var entityIndexMapper = new EntityIndexMapper(connection.GetEntityMapper(typeof(CompoundIndexModel))); - var indexMapping = entityIndexMapper.GetIndexMapping(); - - var indexModel = processor.BuildIndexModel(indexMapping); + var indexModel = IndexModelBuilder.BuildModel(); Assert.AreEqual(1, indexModel.Count()); @@ -131,12 +110,7 @@ public void CompoundIndex() [TestMethod] public void NestedCompoundIndex() { - var connection = TestConfiguration.GetConnection(); - var processor = new BasicIndexProcessor(); - var entityIndexMapper = new EntityIndexMapper(connection.GetEntityMapper(typeof(NestedIndexBaseModel))); - var indexMapping = entityIndexMapper.GetIndexMapping(); - - var indexModel = processor.BuildIndexModel(indexMapping); + var indexModel = IndexModelBuilder.BuildModel(); Assert.AreEqual(1, indexModel.Count()); diff --git a/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs b/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs index 2b41fb89..93559d18 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs @@ -13,7 +13,7 @@ public class TestProcessor : ILinqProcessor where TEntity : cl { public bool EntityProcessed { get; private set; } - public void ProcessEntity(TEntity entity) + public void ProcessEntity(TEntity entity, IMongoDbConnection connection) { EntityProcessed = true; } @@ -29,12 +29,11 @@ public class MongoFrameworkQueryableModel public void EnumerateQueryable() { var connection = TestConfiguration.GetConnection(); - //new EntityMapper(); var collection = connection.GetDatabase().GetCollection(nameof(MongoFrameworkQueryableModel)); var underlyingQueryable = collection.AsQueryable(); var queryable = new MongoFrameworkQueryable(connection, underlyingQueryable); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(MongoFrameworkQueryableModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); entityContainer.Update(new MongoFrameworkQueryableModel { Title = "EnumerateQueryable" }, EntityEntryState.Added); writer.Write(entityContainer); @@ -49,7 +48,6 @@ public void EnumerateQueryable() public void EntityProcessorsFiresOnEnumerationOfTEntity() { var connection = TestConfiguration.GetConnection(); - //new EntityMapper(); var collection = connection.GetDatabase().GetCollection(nameof(MongoFrameworkQueryableModel)); var underlyingQueryable = collection.AsQueryable(); var queryable = new MongoFrameworkQueryable(connection, underlyingQueryable); @@ -57,7 +55,7 @@ public void EntityProcessorsFiresOnEnumerationOfTEntity() var processor = new TestProcessor(); queryable.EntityProcessors.Add(processor); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(MongoFrameworkQueryableModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); entityContainer.Update(new MongoFrameworkQueryableModel { Title = "EntityProcessorFireTest" }, EntityEntryState.Added); writer.Write(entityContainer); @@ -74,7 +72,6 @@ public void EntityProcessorsFiresOnEnumerationOfTEntity() public void EntityProcessorsNotFiredWhenNotTEntity() { var connection = TestConfiguration.GetConnection(); - //new EntityMapper(); var collection = connection.GetDatabase().GetCollection(nameof(MongoFrameworkQueryableModel)); var underlyingQueryable = collection.AsQueryable(); var queryable = new MongoFrameworkQueryable(connection, underlyingQueryable); @@ -82,7 +79,7 @@ public void EntityProcessorsNotFiredWhenNotTEntity() var processor = new TestProcessor(); queryable.EntityProcessors.Add(processor); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(MongoFrameworkQueryableModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); entityContainer.Update(new MongoFrameworkQueryableModel { Title = "EntityProcessorNoFireTest" }, EntityEntryState.Added); writer.Write(entityContainer); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs new file mode 100644 index 00000000..b9470981 --- /dev/null +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityDefinitionExtensionTests.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MongoFramework.Infrastructure.Mapping; + +namespace MongoFramework.Tests.Infrastructure.Mapping +{ + [TestClass] + public class EntityDefinitionExtensionTests : 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 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 TraverseMapping() + { + var definition = EntityMapping.RegisterType(typeof(TraverseMappingModel)); + var result = definition.TraverseProperties().ToArray(); + + Assert.AreEqual(14, 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")); + + 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")); + } + + } +} diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMapperTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMapperTests.cs deleted file mode 100644 index b6a2153a..00000000 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMapperTests.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MongoFramework.Infrastructure.Mapping; -using System; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Threading.Tasks; - -namespace MongoFramework.Tests.Infrastructure.Mapping -{ - [TestClass] - public class EntityMapperTests : TestBase - { - public class MappingLockModel - { - public string Id { get; set; } - } - - [Table("CustomCollection")] - public class CustomCollectionModel - { - } - - [Table("CustomCollection", Schema = "CustomSchema")] - public class CustomCollectionAndSchemaModel - { - } - - public class DefaultCollectionNameModel - { - } - - public class TraverseMappingModel - { - public string Id { get; set; } - public NestedTraverseMappingModel NestedModel { get; set; } - public NestedTraverseMappingModel RepeatedType { get; set; } - public TraverseMappingModel RecursionType { 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 CollectionNameFromClassName() - { - var connection = TestConfiguration.GetConnection(); - var mapper = new EntityMapper(connection); - Assert.AreEqual("DefaultCollectionNameModel", mapper.GetCollectionName()); - } - - [TestMethod] - public void CollectionNameFromAttribute() - { - var connection = TestConfiguration.GetConnection(); - var mapper = new EntityMapper(connection); - Assert.AreEqual("CustomCollection", mapper.GetCollectionName()); - } - - [TestMethod] - public void CollectionNameAndSchemaFromAttribute() - { - var connection = TestConfiguration.GetConnection(); - var mapper = new EntityMapper(connection); - Assert.AreEqual("CustomSchema.CustomCollection", mapper.GetCollectionName()); - } - - [TestMethod] - public void TraverseMapping() - { - var connection = TestConfiguration.GetConnection(); - var mapper = new EntityMapper(connection); - var result = mapper.TraverseMapping().ToArray(); - - Assert.AreEqual(14, 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")); - - 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")); - } - - /// - /// A potentially common issue for web application startup, this tests that multiple threads - /// can map a class at the same time without concurrency issues. - /// - /// Relates to: https://github.com/TurnerSoftware/MongoFramework/issues/7 - /// - [TestMethod] - public void MappingLocks() - { - var connection = TestConfiguration.GetConnection(); - AssertExtensions.DoesNotThrow(() => - { - Parallel.For(1, 10, i => { new EntityMapper(connection); }); - }); - } - } -} \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMappingTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMappingTests.cs new file mode 100644 index 00000000..c300a940 --- /dev/null +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/EntityMappingTests.cs @@ -0,0 +1,34 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MongoFramework.Infrastructure.Mapping; +using System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Threading.Tasks; + +namespace MongoFramework.Tests.Infrastructure.Mapping +{ + [TestClass] + public class EntityMappingTests : TestBase + { + public class MappingLockModel + { + public string Id { get; set; } + } + + /// + /// A potentially common issue for web application startup, this tests that multiple threads + /// can map a class at the same time without concurrency issues. + /// + /// Relates to: https://github.com/TurnerSoftware/MongoFramework/issues/7 + /// + [TestMethod] + public void MappingLocks() + { + var connection = TestConfiguration.GetConnection(); + AssertExtensions.DoesNotThrow(() => + { + Parallel.For(1, 10, i => { EntityMapping.GetOrCreateDefinition(typeof(MappingLockModel)); }); + }); + } + } +} \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/MappingTestBase.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/MappingTestBase.cs new file mode 100644 index 00000000..6737bbea --- /dev/null +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/MappingTestBase.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MongoFramework.Infrastructure.Mapping; + +namespace MongoFramework.Tests.Infrastructure.Mapping +{ + [TestClass] + public abstract class MappingTestBase : TestBase + { + [TestInitialize] + public void MappingProcessorReset() + { + EntityMapping.RemoveAllMappingProcessors(); + } + } +} diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/BsonKnowTypesProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/BsonKnownTypesProcessorTests.cs similarity index 65% rename from tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/BsonKnowTypesProcessorTests.cs rename to tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/BsonKnownTypesProcessorTests.cs index a4ea23a8..be4159b4 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/BsonKnowTypesProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/BsonKnownTypesProcessorTests.cs @@ -1,12 +1,13 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mapping.Processors; namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class BsonKnowTypesProcessorTests : TestBase + public class BsonKnownTypesProcessorTests : MappingTestBase { [BsonKnownTypes(typeof(KnownTypesChildModel))] class KnownTypesBaseModel @@ -32,22 +33,18 @@ class UnknownTypesChildModel : UnknownTypesBaseModel [TestMethod] public void WithAttribute() { - var connection = TestConfiguration.GetConnection(); - var processor = new BsonKnownTypesProcessor(); - var classMap = new BsonClassMap(); + EntityMapping.AddMappingProcessor(new BsonKnownTypesProcessor()); Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(KnownTypesChildModel))); - processor.ApplyMapping(typeof(KnownTypesBaseModel), classMap, connection); + EntityMapping.RegisterType(typeof(KnownTypesBaseModel)); Assert.IsTrue(BsonClassMap.IsClassMapRegistered(typeof(KnownTypesChildModel))); } [TestMethod] public void WithoutAttribute() { - var connection = TestConfiguration.GetConnection(); - var processor = new BsonKnownTypesProcessor(); - var classMap = new BsonClassMap(); + EntityMapping.AddMappingProcessor(new BsonKnownTypesProcessor()); Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(UnknownTypesChildModel))); - processor.ApplyMapping(typeof(UnknownTypesBaseModel), classMap, connection); + EntityMapping.RegisterType(typeof(UnknownTypesBaseModel)); Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(UnknownTypesChildModel))); } } diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/CollectionNameProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/CollectionNameProcessorTests.cs new file mode 100644 index 00000000..45fe4fd3 --- /dev/null +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/CollectionNameProcessorTests.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MongoFramework.Infrastructure.Mapping; +using MongoFramework.Infrastructure.Mapping.Processors; + +namespace MongoFramework.Tests.Infrastructure.Mapping.Processors +{ + [TestClass] + public class CollectionNameProcessorTests : MappingTestBase + { + [Table("CustomCollection")] + public class CustomCollectionModel + { + } + + [Table("CustomCollection", Schema = "CustomSchema")] + public class CustomCollectionAndSchemaModel + { + } + + public class DefaultCollectionNameModel + { + } + + + [TestMethod] + public void CollectionNameFromClassName() + { + EntityMapping.AddMappingProcessor(new CollectionNameProcessor()); + var definition = EntityMapping.RegisterType(typeof(DefaultCollectionNameModel)); + Assert.AreEqual("DefaultCollectionNameModel", definition.CollectionName); + } + + [TestMethod] + public void CollectionNameFromAttribute() + { + EntityMapping.AddMappingProcessor(new CollectionNameProcessor()); + var definition = EntityMapping.RegisterType(typeof(CustomCollectionModel)); + Assert.AreEqual("CustomCollection", definition.CollectionName); + } + + [TestMethod] + public void CollectionNameAndSchemaFromAttribute() + { + EntityMapping.AddMappingProcessor(new CollectionNameProcessor()); + var definition = EntityMapping.RegisterType(typeof(CustomCollectionAndSchemaModel)); + Assert.AreEqual("CustomSchema.CustomCollection", definition.CollectionName); + } + } +} diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs index bfb5c27f..973038a0 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs @@ -2,14 +2,16 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.IdGenerators; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mapping.Processors; using System; using System.ComponentModel.DataAnnotations; +using System.Linq; namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class EntityIdProcessorTests : TestBase + public class EntityIdProcessorTests : MappingTestBase { public class GuidIdGeneratorTestModel { @@ -38,22 +40,19 @@ public class StringIdGeneratorTestModel [TestMethod] public void IdMapsOnAttribute() { - var connection = TestConfiguration.GetConnection(); - var processor = new EntityIdProcessor(); - var classMap = new BsonClassMap(); - processor.ApplyMapping(typeof(IdByAttributeTestModel), classMap, connection); - - var entityMapper = connection.GetEntityMapper(typeof(IdByAttributeTestModel)); - Assert.AreEqual("MyCustomId", entityMapper.GetIdName()); + EntityMapping.AddMappingProcessor(new EntityIdProcessor()); + var definition = EntityMapping.RegisterType(typeof(IdByAttributeTestModel)); + Assert.AreEqual("MyCustomId", definition.GetIdName()); } [TestMethod] public void StringIdGeneratorOnStringProperty() { - var connection = TestConfiguration.GetConnection(); - var processor = new EntityIdProcessor(); - var classMap = new BsonClassMap(); - processor.ApplyMapping(typeof(StringIdGeneratorTestModel), classMap, connection); + EntityMapping.AddMappingProcessor(new EntityIdProcessor()); + EntityMapping.RegisterType(typeof(StringIdGeneratorTestModel)); + + var classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == typeof(StringIdGeneratorTestModel)).FirstOrDefault(); Assert.AreEqual(typeof(StringObjectIdGenerator), classMap.IdMemberMap.IdGenerator?.GetType()); } @@ -61,10 +60,11 @@ public void StringIdGeneratorOnStringProperty() [TestMethod] public void GuidIdGeneratorOnGuidProperty() { - var connection = TestConfiguration.GetConnection(); - var processor = new EntityIdProcessor(); - var classMap = new BsonClassMap(); - processor.ApplyMapping(typeof(GuidIdGeneratorTestModel), classMap, connection); + EntityMapping.AddMappingProcessor(new EntityIdProcessor()); + EntityMapping.RegisterType(typeof(GuidIdGeneratorTestModel)); + + var classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == typeof(GuidIdGeneratorTestModel)).FirstOrDefault(); Assert.AreEqual(typeof(CombGuidGenerator), classMap.IdMemberMap.IdGenerator?.GetType()); } @@ -72,10 +72,11 @@ public void GuidIdGeneratorOnGuidProperty() [TestMethod] public void ObjectIdGeneratorOnObjectIdProperty() { - var connection = TestConfiguration.GetConnection(); - var processor = new EntityIdProcessor(); - var classMap = new BsonClassMap(); - processor.ApplyMapping(typeof(ObjectIdGeneratorTestModel), classMap, connection); + EntityMapping.AddMappingProcessor(new EntityIdProcessor()); + EntityMapping.RegisterType(typeof(ObjectIdGeneratorTestModel)); + + var classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == typeof(ObjectIdGeneratorTestModel)).FirstOrDefault(); Assert.AreEqual(typeof(ObjectIdGenerator), classMap.IdMemberMap.IdGenerator?.GetType()); } diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs new file mode 100644 index 00000000..4922a99b --- /dev/null +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MongoDB.Bson; +using MongoFramework.Infrastructure.Mapping; +using MongoFramework.Infrastructure.Mapping.Processors; +using MongoFramework.Tests.Infrastructure.EntityRelationships; + +namespace MongoFramework.Tests.Infrastructure.Mapping.Processors +{ + [TestClass] + public class EntityRelationshipProcessorTests : MappingTestBase + { + public class BaseEntityModel + { + public string Id { get; set; } + public string Description { get; set; } + + [ForeignKey("CreatedBy")] + public string CreatedById { get; set; } + public virtual UserEntityModel CreatedBy { get; set; } + + public string UpdatedById { get; set; } + [ForeignKey("UpdatedById")] + public virtual UserEntityModel UpdatedBy { get; set; } + } + + public class BaseVariedIdModel + { + public string Id { get; set; } + + [ForeignKey("GuidProperty")] + public Guid GuidTestId { get; set; } + public virtual GuidIdModel GuidProperty { get; set; } + + [ForeignKey("ObjectIdProperty")] + public ObjectId ObjectIdTestId { get; set; } + public virtual ObjectIdIdModel ObjectIdProperty { get; set; } + } + + public class InvalidForeignKeyModel + { + public string Id { get; set; } + + [ForeignKey("Created_By")] + public string CreatedById { get; set; } + public virtual UserEntityModel CreatedBy { get; set; } + } + + public class UnsupportedIdModel + { + public string Id { get; set; } + + [ForeignKey("CreatedBy")] + public int CreatedById { get; set; } + public virtual UserEntityModel CreatedBy { get; set; } + } + + public class UserEntityModel + { + public string Id { get; set; } + public string Username { get; set; } + } + + public class CollectionMappingModel + { + public string Id { get; set; } + public string Description { get; set; } + + public virtual ICollection StringModelEntities { get; set; } + public virtual ICollection ObjectIdModelEntities { get; set; } + public virtual ICollection GuidModelEntities { get; set; } + + [InverseProperty("SecondaryId")] + public virtual ICollection InverseCollection { get; set; } + } + + public class InversePropertyMappingInvalidPropertyTypeModel + { + public string Id { get; set; } + + [InverseProperty("CreatedDate")] + public virtual ICollection StringModelEntities { get; set; } + } + + public class InversePropertyNonExistantPropertyModel + { + public string Id { get; set; } + + [InverseProperty("NonExistantPropertyId")] + public virtual ICollection StringModelEntities { get; set; } + } + + public class ValidInversePropertyModel + { + public string Id { get; set; } + + [InverseProperty("SecondaryId")] + public virtual ICollection StringModelEntities { get; set; } + } + + + [TestMethod] + public void ForeignKeyAttributeOnId() + { + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + + var definition = EntityMapping.RegisterType(typeof(BaseEntityModel)); + var relationships = definition.Relationships; + + var createdByIdProperty = definition.GetProperty("CreatedById"); + var attributeOnIdRelationship = relationships.Where(r => r.IdProperty == createdByIdProperty).FirstOrDefault(); + + Assert.IsFalse(attributeOnIdRelationship.IsCollection); + Assert.AreEqual(typeof(UserEntityModel), attributeOnIdRelationship.EntityType); + Assert.AreEqual(definition.GetProperty("CreatedBy"), attributeOnIdRelationship.NavigationProperty); + } + + [TestMethod] + public void ForeignKeyAttributeOnNavigationProperty() + { + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + + var definition = EntityMapping.RegisterType(typeof(BaseEntityModel)); + var relationships = definition.Relationships; + + var updatedByIdProperty = definition.GetProperty("UpdatedById"); + var attributeOnIdRelationship = relationships.Where(r => r.IdProperty == updatedByIdProperty).FirstOrDefault(); + + Assert.IsFalse(attributeOnIdRelationship.IsCollection); + Assert.AreEqual(typeof(UserEntityModel), attributeOnIdRelationship.EntityType); + Assert.AreEqual(definition.GetProperty("UpdatedBy"), attributeOnIdRelationship.NavigationProperty); + } + + [TestMethod] + public void IdentifyRelationshipsWithOtherIdTypes() + { + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + + var relationships = EntityMapping.RegisterType(typeof(BaseVariedIdModel)).Relationships; + Assert.AreEqual(2, relationships.Count()); + } + + [TestMethod] + [ExpectedExceptionPattern(typeof(InvalidOperationException), @"Unable to determine the Id property between .+ and .+\. Check the types for these properties are correct\.")] + public void UnsupportedIdTypeOnRelationship() + { + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + + EntityMapping.RegisterType(typeof(UnsupportedIdModel)); + } + + [TestMethod] + [ExpectedExceptionPattern(typeof(InvalidOperationException), @"Can't find property .+ in .+ as indicated by the ForeignKeyAttribute.")] + public void InvalidForeignKeyOnRelationship() + { + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + + EntityMapping.RegisterType(typeof(InvalidForeignKeyModel)); + } + + [TestMethod] + public void NavigationPropertiesUnmap() + { + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + + var definition = EntityMapping.RegisterType(typeof(BaseEntityModel)); + + Assert.IsFalse(definition.Properties.Any(e => e.FullPath == "CreatedBy" || e.FullPath == "UpdatedBy")); + } + + [TestMethod] + public void IdentifyCollectionRelationships() + { + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + + var definition = EntityMapping.RegisterType(typeof(CollectionMappingModel)); + var relationships = definition.Relationships; + + Assert.IsTrue(relationships.All(r => r.IsCollection)); + + var relationship = relationships.Where(r => r.NavigationProperty.PropertyInfo.Name == "StringModelEntities").FirstOrDefault(); + var stringIdModelDefinition = EntityMapping.GetOrCreateDefinition(typeof(StringIdModel)); + + Assert.IsTrue(relationship.IsCollection); + Assert.AreEqual(typeof(StringIdModel), relationship.EntityType); + Assert.AreEqual(stringIdModelDefinition.GetProperty("Id"), relationship.IdProperty); + Assert.AreEqual(definition.GetProperty("StringModelEntities"), relationship.NavigationProperty); + } + + [TestMethod] + public void ValidInversePropertyMapping() + { + var relationships = EntityMapping.RegisterType(typeof(ValidInversePropertyModel)).Relationships; + + Assert.IsTrue(relationships.Any(r => r.IsCollection && r.IdProperty.PropertyInfo.Name == "SecondaryId")); + } + + [TestMethod] + [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+ in .+")] + public void InversePropertyMappingNonExistantProperty() + { + EntityMapping.RegisterType(typeof(InversePropertyNonExistantPropertyModel)); + } + + [TestMethod] + [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+ in .+")] + public void InversePropertyMappingInvalidPropertyType() + { + EntityMapping.RegisterType(typeof(InversePropertyMappingInvalidPropertyTypeModel)); + } + } +} diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs index b74260ce..46222b72 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/ExtraElementsProcessorTests.cs @@ -1,13 +1,15 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson.Serialization; using MongoFramework.Attributes; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mapping.Processors; using System.Collections.Generic; +using System.Linq; namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class ExtraElementsProcessorTests : TestBase + public class ExtraElementsProcessorTests : MappingTestBase { public class ExtraElementsModel { @@ -25,25 +27,33 @@ public class IgnoreExtraElementsModel [TestMethod] public void ObeysIgnoreExtraElementsAttribute() { - var connection = TestConfiguration.GetConnection(); - var processor = new ExtraElementsProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - processor.ApplyMapping(typeof(IgnoreExtraElementsModel), classMap, connection); + EntityMapping.AddMappingProcessor(new ExtraElementsProcessor()); + EntityMapping.RegisterType(typeof(IgnoreExtraElementsModel)); + var classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == typeof(IgnoreExtraElementsModel)).FirstOrDefault(); Assert.IsTrue(classMap.IgnoreExtraElements); + + EntityMapping.RegisterType(typeof(ExtraElementsModel)); + classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == typeof(ExtraElementsModel)).FirstOrDefault(); + Assert.IsFalse(classMap.IgnoreExtraElements); } [TestMethod] public void ObeysExtraElementsAttribute() { - var connection = TestConfiguration.GetConnection(); - var processor = new ExtraElementsProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - processor.ApplyMapping(typeof(ExtraElementsModel), classMap, connection); + EntityMapping.AddMappingProcessor(new ExtraElementsProcessor()); + EntityMapping.RegisterType(typeof(ExtraElementsModel)); + + var classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == typeof(ExtraElementsModel)).FirstOrDefault(); + Assert.AreEqual("AdditionalElements", classMap.ExtraElementsMemberMap.ElementName); - Assert.AreEqual("AdditionalElements", classMap.ExtraElementsMemberMap?.ElementName); + EntityMapping.RegisterType(typeof(IgnoreExtraElementsModel)); + classMap = BsonClassMap.GetRegisteredClassMaps() + .Where(cm => cm.ClassType == typeof(IgnoreExtraElementsModel)).FirstOrDefault(); + Assert.AreEqual(null, classMap.ExtraElementsMemberMap); } } } \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs index 3f40c2b4..97877172 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs @@ -1,12 +1,13 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson.Serialization; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mapping.Processors; using System.Linq; namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class HierarchyProcessorTests : TestBase + public class HierarchyProcessorTests : MappingTestBase { public class ParentTestModel { @@ -18,30 +19,47 @@ public class ChildTestModel : ParentTestModel public string DeclaredProperty { get; set; } } + [TestMethod] + public void ParentClassIsMapped() + { + EntityMapping.AddMappingProcessor(new HierarchyProcessor()); + + Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(ChildTestModel))); + Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(ParentTestModel))); + + EntityMapping.RegisterType(typeof(ChildTestModel)); + + Assert.IsTrue(BsonClassMap.IsClassMapRegistered(typeof(ChildTestModel))); + Assert.IsTrue(BsonClassMap.IsClassMapRegistered(typeof(ParentTestModel))); + } + [TestMethod] public void AccessToInherittedProperty() { - var connection = TestConfiguration.GetConnection(); - var processor = new HierarchyProcessor(); - var classMap = new BsonClassMap(); - processor.ApplyMapping(typeof(ChildTestModel), classMap, connection); - - var entityMapper = connection.GetEntityMapper(typeof(ChildTestModel)); - var mappedProperties = entityMapper.GetEntityMapping(); - Assert.IsTrue(mappedProperties.Any(p => p.ElementName == "Id")); + EntityMapping.AddMappingProcessor(new HierarchyProcessor()); + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + + var definition = EntityMapping.RegisterType(typeof(ChildTestModel)); + + var allProperties = definition.GetAllProperties(); + Assert.IsTrue(allProperties.Any(p => p.ElementName == "Id")); + + var declaredProperties = definition.Properties; + Assert.IsFalse(declaredProperties.Any(p => p.ElementName == "Id")); } [TestMethod] public void AccessToDeclaredProperty() { - var connection = TestConfiguration.GetConnection(); - var processor = new HierarchyProcessor(); - var classMap = new BsonClassMap(); - processor.ApplyMapping(typeof(ChildTestModel), classMap, connection); + EntityMapping.AddMappingProcessor(new HierarchyProcessor()); + EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + var definition = EntityMapping.RegisterType(typeof(ChildTestModel)); - var entityMapper = connection.GetEntityMapper(typeof(ChildTestModel)); - var mappedProperties = entityMapper.GetEntityMapping(); + var mappedProperties = definition.GetAllProperties(); Assert.IsTrue(mappedProperties.Any(p => p.ElementName == "DeclaredProperty")); + + var inherittedProperties = definition.GetInheritedProperties(); + Assert.IsFalse(inherittedProperties.Any(p => p.ElementName == "DeclaredProperty")); } } } \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs index 5f9569e3..d499801a 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson.Serialization; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mapping.Processors; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; @@ -7,7 +8,7 @@ namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class MappedPropertiesProcessorTests : TestBase + public class MappedPropertiesProcessorTests : MappingTestBase { public class ColumnAttributePropertyModel { @@ -26,29 +27,17 @@ public class NotMappedPropertiesModel [TestMethod] public void ObeysNotMappedAttribute() { - var connection = TestConfiguration.GetConnection(); - var processor = new MappedPropertiesProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - processor.ApplyMapping(typeof(NotMappedPropertiesModel), classMap, connection); - - var entityMapper = connection.GetEntityMapper(typeof(NotMappedPropertiesModel)); - var mappedProperties = entityMapper.GetEntityMapping(); - Assert.IsFalse(mappedProperties.Any(p => p.ElementName == "NotMapped")); + EntityMapping.AddMappingProcessor(new MappedPropertiesProcessor()); + var definition = EntityMapping.RegisterType(typeof(NotMappedPropertiesModel)); + Assert.IsFalse(definition.Properties.Any(p => p.ElementName == "NotMapped")); } [TestMethod] public void ObeysColumnAttributeRemap() { - var connection = TestConfiguration.GetConnection(); - var processor = new MappedPropertiesProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - processor.ApplyMapping(typeof(ColumnAttributePropertyModel), classMap, connection); - - var entityMapper = connection.GetEntityMapper(typeof(ColumnAttributePropertyModel)); - var mappedProperties = entityMapper.GetEntityMapping(); - Assert.IsTrue(mappedProperties.Any(p => p.ElementName == "CustomPropertyName")); + EntityMapping.AddMappingProcessor(new MappedPropertiesProcessor()); + var definition = EntityMapping.RegisterType(typeof(ColumnAttributePropertyModel)); + Assert.IsTrue(definition.Properties.Any(p => p.ElementName == "CustomPropertyName")); } } } \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedPropertyProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedPropertyProcessorTests.cs index a90dfdc9..8b6c2e0e 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedPropertyProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedPropertyProcessorTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson.Serialization; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mapping.Processors; using System.Collections.Generic; using System.Linq; @@ -7,7 +8,7 @@ namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class NestedPropertyProcessorTests : TestBase + public class NestedPropertyProcessorTests : MappingTestBase { public class CollectionBaseModel { @@ -32,35 +33,19 @@ public class PropertyNestedModel [TestMethod] public void MapsNestedStandardPropertyModel() { - var connection = TestConfiguration.GetConnection(); - var processor = new NestedPropertyProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - - var registeredClassMaps = BsonClassMap.GetRegisteredClassMaps(); - Assert.IsFalse(registeredClassMaps.Any(m => m.ClassType == typeof(PropertyNestedModel))); - - processor.ApplyMapping(typeof(PropertyBaseModel), classMap, connection); - - registeredClassMaps = BsonClassMap.GetRegisteredClassMaps(); - Assert.IsTrue(registeredClassMaps.Any(m => m.ClassType == typeof(PropertyNestedModel))); + EntityMapping.AddMappingProcessor(new NestedPropertyProcessor()); + Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(PropertyNestedModel))); + EntityMapping.RegisterType(typeof(PropertyBaseModel)); + Assert.IsTrue(BsonClassMap.IsClassMapRegistered(typeof(PropertyNestedModel))); } [TestMethod] public void MapsNestedCollectionPropertyModel() { - var connection = TestConfiguration.GetConnection(); - var processor = new NestedPropertyProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - - var registeredClassMaps = BsonClassMap.GetRegisteredClassMaps(); - Assert.IsFalse(registeredClassMaps.Any(m => m.ClassType == typeof(CollectionNestedModel))); - - processor.ApplyMapping(typeof(CollectionBaseModel), classMap, connection); - - registeredClassMaps = BsonClassMap.GetRegisteredClassMaps(); - Assert.IsTrue(registeredClassMaps.Any(m => m.ClassType == typeof(CollectionNestedModel))); + EntityMapping.AddMappingProcessor(new NestedPropertyProcessor()); + Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(CollectionNestedModel))); + EntityMapping.RegisterType(typeof(CollectionBaseModel)); + Assert.IsTrue(BsonClassMap.IsClassMapRegistered(typeof(CollectionNestedModel))); } } } \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs index 73daa208..e5549bcc 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs @@ -1,13 +1,14 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MongoDB.Bson.Serialization; using MongoFramework.Attributes; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Infrastructure.Mapping.Processors; -using MongoFramework.Infrastructure.Mapping.Serialization; +using MongoFramework.Infrastructure.Serialization; namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class TypeDiscoveryProcessorTests : TestBase + public class TypeDiscoveryProcessorTests : MappingTestBase { public class NoTypeDiscoveryAttributeModel { @@ -23,33 +24,29 @@ public class TypeDiscoveryAttributeModel [TestMethod] public void TypeDiscoverySerializerWhenAttributeIsDefined() { - var connection = TestConfiguration.GetConnection(); - var processor = new TypeDiscoveryProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - BsonClassMap.RegisterClassMap(classMap); - - processor.ApplyMapping(typeof(TypeDiscoveryAttributeModel), classMap, connection); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); var serializer = BsonSerializer.LookupSerializer(); + Assert.AreNotEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); + EntityMapping.RegisterType(typeof(TypeDiscoveryAttributeModel)); + + serializer = BsonSerializer.LookupSerializer(); Assert.AreEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); } [TestMethod] public void NotTypeDiscoverySerializerWhenAttributeNotDefined() { - var connection = TestConfiguration.GetConnection(); - var processor = new TypeDiscoveryProcessor(); - var classMap = new BsonClassMap(); - classMap.AutoMap(); - BsonClassMap.RegisterClassMap(classMap); - - processor.ApplyMapping(typeof(NoTypeDiscoveryAttributeModel), classMap, connection); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); var serializer = BsonSerializer.LookupSerializer(); - Assert.AreNotEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); + + EntityMapping.RegisterType(typeof(NoTypeDiscoveryAttributeModel)); + + serializer = BsonSerializer.LookupSerializer(); + Assert.AreNotEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition());; } } } diff --git a/tests/MongoFramework.Tests/Infrastructure/Mutation/Mutators/IncrementNumberMutatorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mutation/Mutators/IncrementNumberMutatorTests.cs deleted file mode 100644 index 5bf76a49..00000000 --- a/tests/MongoFramework.Tests/Infrastructure/Mutation/Mutators/IncrementNumberMutatorTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MongoFramework.Attributes; -using MongoFramework.Infrastructure.Mutation; -using MongoFramework.Infrastructure.Mutation.Mutators; - -namespace MongoFramework.Tests.Infrastructure.Mutation.Mutators -{ - [TestClass] - public class IncrementNumberMutatorTests : TestBase - { - public class IncrementalEntity - { - [IncrementNumber] - public int ByDefault { get; set; } - [IncrementNumber(true)] - public int ByUpdateOnly { get; set; } - [IncrementNumber(10)] - public int ByTen { get; set; } - } - - private IncrementalEntity Mutate(MutatorType type, IncrementalEntity entity = null) - { - entity = entity ?? new IncrementalEntity(); - var connection = TestConfiguration.GetConnection(); - var mutator = new EntityAttributeMutator(); - - mutator.MutateEntity(entity, type, connection); - return entity; - } - - [TestMethod] - public void OnDefaultInsert() - { - var entity = Mutate(MutatorType.Insert); - Assert.AreEqual(1, entity.ByDefault); - } - - [TestMethod] - public void OnDefaultUpdate() - { - var entity = Mutate(MutatorType.Update); - Assert.AreEqual(1, entity.ByDefault); - } - - [TestMethod] - public void OnUpdateMultipleTimes() - { - var entity = Mutate(MutatorType.Update); - Assert.AreEqual(1, entity.ByDefault); - entity = Mutate(MutatorType.Update, entity); - Assert.AreEqual(2, entity.ByDefault); - entity = Mutate(MutatorType.Update, entity); - Assert.AreEqual(3, entity.ByDefault); - } - - [TestMethod] - public void IncrementOnUpdateOnly() - { - var entity = Mutate(MutatorType.Insert); - Assert.AreEqual(0, entity.ByUpdateOnly); - entity = Mutate(MutatorType.Update); - Assert.AreEqual(1, entity.ByUpdateOnly); - } - - public void IncrementByTen() - { - var entity = Mutate(MutatorType.Insert); - Assert.AreEqual(10, entity.ByTen); - } - } -} \ No newline at end of file diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionSerializerTests.cs b/tests/MongoFramework.Tests/Infrastructure/Serialization/EntityNavigationCollectionSerializerTests.cs similarity index 84% rename from tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionSerializerTests.cs rename to tests/MongoFramework.Tests/Infrastructure/Serialization/EntityNavigationCollectionSerializerTests.cs index 941ccd77..5cf9f20c 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionSerializerTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Serialization/EntityNavigationCollectionSerializerTests.cs @@ -2,12 +2,15 @@ using MongoDB.Bson; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; -using MongoFramework.Infrastructure.EntityRelationships; +using MongoFramework.Infrastructure; +using MongoFramework.Infrastructure.Mapping; +using MongoFramework.Infrastructure.Serialization; +using MongoFramework.Tests.Infrastructure.EntityRelationships; using System; using System.Collections.Generic; using System.Linq; -namespace MongoFramework.Tests.Infrastructure.EntityRelationships +namespace MongoFramework.Tests.Infrastructure.Serialization { [TestClass] public class EntityNavigationCollectionSerializerTests : TestBase @@ -15,8 +18,8 @@ public class EntityNavigationCollectionSerializerTests : TestBase [TestMethod] public void DeserializingNullReturnsCollection() { - var connection = TestConfiguration.GetConnection(); - var serializer = new EntityNavigationCollectionSerializer("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(StringIdModel)).GetIdProperty(); + var serializer = new EntityNavigationCollectionSerializer(foreignProperty); var document = new BsonDocument(new Dictionary { @@ -42,8 +45,8 @@ public void DeserializingNullReturnsCollection() [ExpectedException(typeof(NotSupportedException))] public void DeserializingInvalidTypeThrowsException() { - var connection = TestConfiguration.GetConnection(); - var serializer = new EntityNavigationCollectionSerializer("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(StringIdModel)).GetIdProperty(); + var serializer = new EntityNavigationCollectionSerializer(foreignProperty); var document = new BsonDocument(new Dictionary { @@ -65,10 +68,10 @@ public void DeserializingInvalidTypeThrowsException() [TestMethod] public void ReserializingStringIdEntityMaintainsStateExceptNulls() { - var connection = TestConfiguration.GetConnection(); - var serializer = new EntityNavigationCollectionSerializer("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(StringIdModel)).GetIdProperty(); + var serializer = new EntityNavigationCollectionSerializer(foreignProperty); - var initialCollection = new EntityNavigationCollection("Id", connection) + var initialCollection = new EntityNavigationCollection(foreignProperty) { new StringIdModel { @@ -116,10 +119,10 @@ public void ReserializingStringIdEntityMaintainsStateExceptNulls() [TestMethod] public void ReserializingObjectIdIdEntityMaintainsState() { - var connection = TestConfiguration.GetConnection(); - var serializer = new EntityNavigationCollectionSerializer("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var serializer = new EntityNavigationCollectionSerializer(foreignProperty); - var initialCollection = new EntityNavigationCollection("Id", connection) + var initialCollection = new EntityNavigationCollection(foreignProperty) { new ObjectIdIdModel { @@ -163,8 +166,8 @@ public void ReserializingObjectIdIdEntityMaintainsState() [TestMethod] public void SerializeICollectionCompatibleButIsntEntityNavigationCollection() { - var connection = TestConfiguration.GetConnection(); - var serializer = new EntityNavigationCollectionSerializer("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var serializer = new EntityNavigationCollectionSerializer(foreignProperty); var initialCollection = new List { @@ -208,8 +211,8 @@ public void SerializeICollectionCompatibleButIsntEntityNavigationCollection() [TestMethod, ExpectedException(typeof(NotSupportedException))] public void SerializeUnsupportedType() { - var connection = TestConfiguration.GetConnection(); - var serializer = new EntityNavigationCollectionSerializer("Id", connection); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var serializer = new EntityNavigationCollectionSerializer(foreignProperty); var initialCollection = new List { diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Serialization/TypeDiscoveryIntegrationTests.cs b/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoveryIntegrationTests.cs similarity index 53% rename from tests/MongoFramework.Tests/Infrastructure/Mapping/Serialization/TypeDiscoveryIntegrationTests.cs rename to tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoveryIntegrationTests.cs index cefa7dac..ecf2aca3 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Serialization/TypeDiscoveryIntegrationTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoveryIntegrationTests.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Reflection; -namespace MongoFramework.Tests.Infrastructure.Mapping.Serialization +namespace MongoFramework.Tests.Infrastructure.Serialization { [TestClass] public class TypeDiscoveryIntegrationTests : TestBase @@ -25,30 +25,6 @@ public class UnknownChildToRootModel : RootKnownBaseModel public string AdditionProperty { get; set; } } - [TestInitialize] - public void ResetMongoDbDriver() - { - var classMapField = typeof(BsonClassMap).GetField("__classMaps", BindingFlags.NonPublic | BindingFlags.Static); - classMapField.SetValue(null, new Dictionary()); - - var knownTypesField = typeof(BsonSerializer).GetField("__typesWithRegisteredKnownTypes", BindingFlags.NonPublic | BindingFlags.Static); - knownTypesField.SetValue(null, new HashSet()); - - var discriminatorTypesField = typeof(BsonSerializer).GetField("__discriminatedTypes", BindingFlags.NonPublic | BindingFlags.Static); - discriminatorTypesField.SetValue(null, new HashSet()); - - var discriminatorsField = typeof(BsonSerializer).GetField("__discriminators", BindingFlags.NonPublic | BindingFlags.Static); - discriminatorsField.SetValue(null, new Dictionary>()); - - 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(); - } - } - [TestMethod] public void ReadAndWriteRootEntity() { @@ -70,7 +46,7 @@ public void ReadAndWriteRootEntity() dbSet.SaveChanges(); - ResetMongoDbDriver(); + ResetMongoDb(); dbSet = new MongoDbSet(); dbSet.SetConnection(connection); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Serialization/TypeDiscoverySerializationTests.cs b/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoverySerializationTests.cs similarity index 81% rename from tests/MongoFramework.Tests/Infrastructure/Mapping/Serialization/TypeDiscoverySerializationTests.cs rename to tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoverySerializationTests.cs index c82d6821..37b4b65f 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Serialization/TypeDiscoverySerializationTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Serialization/TypeDiscoverySerializationTests.cs @@ -3,10 +3,12 @@ using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoFramework.Attributes; -using MongoFramework.Infrastructure.Mapping.Serialization; +using MongoFramework.Infrastructure.Mapping; +using MongoFramework.Infrastructure.Mapping.Processors; +using MongoFramework.Infrastructure.Serialization; using System.Collections.Generic; -namespace MongoFramework.Tests.Infrastructure.Mapping.Serialization +namespace MongoFramework.Tests.Infrastructure.Serialization { [TestClass] public class TypeDiscoverySerializationTests : TestBase @@ -32,8 +34,9 @@ public class UnknownGrandChildModel : UnknownChildModel [TestMethod] public void NullDeserialization() { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(KnownBaseModel)); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); + EntityMapping.RegisterType(typeof(KnownBaseModel)); + var serializer = TypeDiscoverySerializationProvider.Instance.GetSerializer(typeof(KnownBaseModel)); var document = new BsonDocument @@ -60,8 +63,8 @@ public void NullDeserialization() [TestMethod] public void DeserializeChildTypeDiscoveryForRootEntity() { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(KnownBaseModel)); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); + EntityMapping.RegisterType(typeof(KnownBaseModel)); var document = new BsonDocument { @@ -75,8 +78,8 @@ public void DeserializeChildTypeDiscoveryForRootEntity() [TestMethod] public void DeserializeGrandChildTypeDiscoveryForRootEntity() { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(KnownBaseModel)); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); + EntityMapping.RegisterType(typeof(KnownBaseModel)); var document = new BsonDocument { @@ -90,8 +93,8 @@ public void DeserializeGrandChildTypeDiscoveryForRootEntity() [TestMethod] public void DeserializeWithoutTypeDiscovery() { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(KnownBaseModel)); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); + EntityMapping.RegisterType(typeof(KnownBaseModel)); TypeDiscoverySerializationProvider.Instance.Enabled = false; @@ -109,8 +112,8 @@ public void DeserializeWithoutTypeDiscovery() [TestMethod] public void DeserializeCollection() { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(CollectionBaseModel)); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); + EntityMapping.RegisterType(typeof(CollectionBaseModel)); var document = new BsonDocument { @@ -144,8 +147,8 @@ public void DeserializeCollection() [TestMethod] public void ReserializationWithoutDataLoss() { - var connection = TestConfiguration.GetConnection(); - var entityMapper = connection.GetEntityMapper(typeof(CollectionBaseModel)); + EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); + EntityMapping.RegisterType(typeof(CollectionBaseModel)); var initialEntity = new CollectionBaseModel { diff --git a/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs b/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs index f58f86a6..05556b71 100644 --- a/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs +++ b/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs @@ -56,7 +56,7 @@ public void WhereIdMatchesGuids() { var connection = TestConfiguration.GetConnection(); var dbEntityWriter = new EntityWriter(TestConfiguration.GetConnection()); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(WhereIdMatchesGuidModel))) + var entityCollection = new EntityCollection() { new WhereIdMatchesGuidModel { Description = "1" }, new WhereIdMatchesGuidModel { Description = "2" }, @@ -82,7 +82,7 @@ public void WhereIdMatchesObjectIds() { var connection = TestConfiguration.GetConnection(); var dbEntityWriter = new EntityWriter(connection); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(WhereIdMatchesObjectIdModel))) + var entityCollection = new EntityCollection() { new WhereIdMatchesObjectIdModel { Description = "1" }, new WhereIdMatchesObjectIdModel { Description = "2" }, @@ -108,7 +108,7 @@ public void WhereIdMatchesStringIds() { var connection = TestConfiguration.GetConnection(); var dbEntityWriter = new EntityWriter(connection); - var entityCollection = new EntityCollection(connection.GetEntityMapper(typeof(WhereIdMatchesStringModel))) + var entityCollection = new EntityCollection() { new WhereIdMatchesStringModel { Description = "1" }, new WhereIdMatchesStringModel { Description = "2" }, diff --git a/tests/MongoFramework.Tests/Infrastructure/MongoDbUtilityTests.cs b/tests/MongoFramework.Tests/MongoDbUtilityTests.cs similarity index 94% rename from tests/MongoFramework.Tests/Infrastructure/MongoDbUtilityTests.cs rename to tests/MongoFramework.Tests/MongoDbUtilityTests.cs index 2aba5fea..b6b6ca0d 100644 --- a/tests/MongoFramework.Tests/Infrastructure/MongoDbUtilityTests.cs +++ b/tests/MongoFramework.Tests/MongoDbUtilityTests.cs @@ -15,7 +15,7 @@ public class MongoDbUtilityModel public void ValidObjectId() { var connection = TestConfiguration.GetConnection(); - var entityContainer = new EntityCollection(connection.GetEntityMapper(typeof(MongoDbUtilityModel))); + var entityContainer = new EntityCollection(); var writer = new EntityWriter(connection); var entity = new MongoDbUtilityModel(); diff --git a/tests/MongoFramework.Tests/Profiling/MiniProfiler/MiniProfilerDiagnosticListenerTests.cs b/tests/MongoFramework.Tests/Profiling/MiniProfiler/MiniProfilerDiagnosticListenerTests.cs index bc0ddcc0..b478f3f2 100644 --- a/tests/MongoFramework.Tests/Profiling/MiniProfiler/MiniProfilerDiagnosticListenerTests.cs +++ b/tests/MongoFramework.Tests/Profiling/MiniProfiler/MiniProfilerDiagnosticListenerTests.cs @@ -10,7 +10,7 @@ public class MiniProfilerDiagnosticListenerTests : TestBase { private IMongoDbConnection GetConnection() { - var connection = MongoDbConnection.FromConnectionString(TestConfiguration.ConnectionString, TestConfiguration.GetDatabaseName()); + var connection = TestConfiguration.GetConnection(); connection.DiagnosticListener = new MiniProfilerDiagnosticListener(); return connection; } diff --git a/tests/MongoFramework.Tests/TestBase.cs b/tests/MongoFramework.Tests/TestBase.cs index b8f30e95..e492d2ed 100644 --- a/tests/MongoFramework.Tests/TestBase.cs +++ b/tests/MongoFramework.Tests/TestBase.cs @@ -2,6 +2,7 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver; +using MongoFramework.Infrastructure.Mapping; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -12,7 +13,13 @@ namespace MongoFramework.Tests [TestClass] public abstract class TestBase { - protected static void ResetMongoDbMapping() + protected static void ResetMongoDb() + { + ResetMongoDbDriver(); + EntityMapping.RemoveAllDefinitions(); + } + + private static void ResetMongoDbDriver() { //Primarily introduced to better test TypeDiscoverySerializer, this is designed to reset the MongoDB driver //as if the assembly just loaded. It is likely incomplete and would be easily subject to breaking in future @@ -46,11 +53,11 @@ protected static void ClearDatabase() client.DropDatabase(TestConfiguration.GetDatabaseName()); } - [TestCleanup] - public void Cleanup() + [TestInitialize] + public void Initialise() { + ResetMongoDb(); ClearDatabase(); - ResetMongoDbMapping(); } [AssemblyCleanup] diff --git a/tests/MongoFramework.Tests/TestConfiguration.cs b/tests/MongoFramework.Tests/TestConfiguration.cs index d6654bc2..e3c2061d 100644 --- a/tests/MongoFramework.Tests/TestConfiguration.cs +++ b/tests/MongoFramework.Tests/TestConfiguration.cs @@ -1,4 +1,5 @@ using System; +using MongoDB.Driver; namespace MongoFramework.Tests { @@ -20,7 +21,11 @@ public static string GetDatabaseName() public static IMongoDbConnection GetConnection() { - return MongoDbConnection.FromConnectionString(ConnectionString, GetDatabaseName()); + var urlBuilder = new MongoUrlBuilder(ConnectionString) + { + DatabaseName = GetDatabaseName() + }; + return MongoDbConnection.FromUrl(urlBuilder.ToMongoUrl()); } } } \ No newline at end of file From 2a0ea49490f4f69abda2fb07a0e310a970d775e7 Mon Sep 17 00:00:00 2001 From: Turnerj Date: Sun, 12 May 2019 18:36:43 +0930 Subject: [PATCH 3/3] Various test tweaks and fixes --- .../Linq/MongoFrameworkQueryable.cs | 7 ++- .../Mapping/DefaultMappingPack.cs | 4 +- .../Mapping/EntityDefinition.cs | 7 +-- .../Mapping/EntityDefinitionExtensions.cs | 14 +++--- .../Infrastructure/Mapping/EntityMapping.cs | 21 ++++----- .../Infrastructure/Mapping/EntityProperty.cs | 15 +++++++ .../Infrastructure/Mapping/IEntityProperty.cs | 2 +- ...ssor.cs => ClassMapPropertiesProcessor.cs} | 2 +- .../Processors/EntityRelationshipProcessor.cs | 2 +- .../Mapping/Processors/HierarchyProcessor.cs | 2 +- .../Mapping/Processors/IndexProcessor.cs | 3 +- ...rtyProcessor.cs => NestedTypeProcessor.cs} | 2 +- .../EntityNavigationCollectionUnitTests.cs | 4 +- .../Linq/MongoFrameworkQueryableTests.cs | 7 +++ .../Processors/EntityIdProcessorTests.cs | 1 + .../EntityRelationshipProcessorTests.cs | 43 +++++++++++-------- .../Processors/HierarchyProcessorTests.cs | 4 +- .../MappedPropertiesProcessorTests.cs | 2 + ...orTests.cs => NestedTypeProcessorTests.cs} | 6 +-- .../Processors/TypeDiscoveryProcessorTests.cs | 12 ++---- .../Linq/LinqExtensionsTests.cs | 3 ++ tests/MongoFramework.Tests/TestBase.cs | 3 ++ 22 files changed, 105 insertions(+), 61 deletions(-) rename src/MongoFramework/Infrastructure/Mapping/Processors/{PropertiesProcessor.cs => ClassMapPropertiesProcessor.cs} (91%) rename src/MongoFramework/Infrastructure/Mapping/Processors/{NestedPropertyProcessor.cs => NestedTypeProcessor.cs} (95%) rename tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/{NestedPropertyProcessorTests.cs => NestedTypeProcessorTests.cs} (86%) diff --git a/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs b/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs index 078eaea8..0836d59a 100644 --- a/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs +++ b/src/MongoFramework/Infrastructure/Linq/MongoFrameworkQueryable.cs @@ -83,7 +83,12 @@ public IEnumerator GetEnumerator() { while (enumerator.MoveNext()) { - yield return enumerator.Current; + var item = enumerator.Current; + if (item is TEntity) + { + EntityProcessors.ProcessEntity((TEntity)(object)item, Connection); + } + yield return item; } } } diff --git a/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs b/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs index 5188a1a0..81d2adcb 100644 --- a/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs +++ b/src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs @@ -15,11 +15,11 @@ private DefaultMappingPack() new HierarchyProcessor(), new EntityIdProcessor(), new MappedPropertiesProcessor(), - new NestedPropertyProcessor(), + new NestedTypeProcessor(), new ExtraElementsProcessor(), new TypeDiscoveryProcessor(), new BsonKnownTypesProcessor(), - new PropertiesProcessor(), + new ClassMapPropertiesProcessor(), new IndexProcessor(), new EntityRelationshipProcessor() }; diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs index d4de6ce0..b9777c87 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace MongoFramework.Infrastructure.Mapping @@ -8,8 +9,8 @@ public class EntityDefinition : IEntityDefinition { public Type EntityType { get; set; } public string CollectionName { get; set; } - public IEnumerable Properties { get; set; } - public IEnumerable Relationships { get; set; } - public IEnumerable Indexes { get; set; } + public IEnumerable Properties { get; set; } = Enumerable.Empty(); + public IEnumerable Relationships { get; set; } = Enumerable.Empty(); + public IEnumerable Indexes { get; set; } = Enumerable.Empty(); } } diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs index d636f213..63bb4ef9 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityDefinitionExtensions.cs @@ -17,7 +17,7 @@ public static IEntityProperty GetIdProperty(this IEntityDefinition definition) public static string GetIdName(this IEntityDefinition definition) { - return definition.Properties.Where(m => m.IsKey).Select(m => m.ElementName).FirstOrDefault(); + return definition.GetIdProperty()?.ElementName; } public static object GetIdValue(this IEntityDefinition definition, object entity) @@ -27,8 +27,8 @@ public static object GetIdValue(this IEntityDefinition definition, object entity public static object GetDefaultId(this IEntityDefinition definition) { - var idPropertyType = definition.GetIdProperty().PropertyType; - if (idPropertyType.IsValueType) + var idPropertyType = definition.GetIdProperty()?.PropertyType; + if (idPropertyType != null && idPropertyType.IsValueType) { return Activator.CreateInstance(idPropertyType); } @@ -38,13 +38,15 @@ public static object GetDefaultId(this IEntityDefinition definition) public static IEnumerable GetInheritedProperties(this IEntityDefinition definition) { var currentType = definition.EntityType.BaseType; - while (currentType != typeof(object)) + while (currentType != typeof(object) && currentType != null) { - var properties = EntityMapping.GetOrCreateDefinition(currentType).Properties; - foreach (var property in properties) + var currentDefinition = EntityMapping.GetOrCreateDefinition(currentType); + foreach (var property in currentDefinition.Properties) { yield return property; } + + currentType = currentType.BaseType; } } diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs index 4f3fa82a..6f6ba144 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityMapping.cs @@ -13,12 +13,12 @@ public class EntityMapping { private static ReaderWriterLockSlim MappingLock { get; } = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); private static ConcurrentDictionary EntityDefinitions { get; } - private static ConcurrentDictionary MappingProcessors { get; } + private static List MappingProcessors { get; } static EntityMapping() { EntityDefinitions = new ConcurrentDictionary(); - MappingProcessors = new ConcurrentDictionary(); + MappingProcessors = new List(); AddMappingProcessors(DefaultMappingPack.Instance.Processors); } @@ -76,7 +76,7 @@ public static IEntityDefinition RegisterType(Type entityType) BsonClassMap.RegisterClassMap(classMap); classMap.AutoMap(); - foreach (var processor in MappingProcessors.Values) + foreach (var processor in MappingProcessors) { processor.ApplyMapping(definition, classMap); } @@ -105,18 +105,19 @@ public static IEntityDefinition GetOrCreateDefinition(Type entityType) public static void AddMappingProcessors(IEnumerable mappingProcessors) { - foreach (var processor in mappingProcessors) - { - MappingProcessors.TryAdd(processor.GetType(), processor); - } + MappingProcessors.AddRange(mappingProcessors); } - public static void AddMappingProcessor(TProcessor mappingProcessor) where TProcessor : IMappingProcessor + public static void AddMappingProcessor(IMappingProcessor mappingProcessor) { - MappingProcessors.TryAdd(typeof(TProcessor), mappingProcessor); + MappingProcessors.Add(mappingProcessor); } public static void RemoveMappingProcessor() where TProcessor : IMappingProcessor { - MappingProcessors.TryRemove(typeof(TProcessor), out _); + var matchingItems = MappingProcessors.Where(p => p.GetType() == typeof(TProcessor)).ToArray(); + foreach (var matchingItem in matchingItems) + { + MappingProcessors.Remove(matchingItem); + } } public static void RemoveAllMappingProcessors() { diff --git a/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs b/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs index 3aaade37..72113f99 100644 --- a/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs +++ b/src/MongoFramework/Infrastructure/Mapping/EntityProperty.cs @@ -12,6 +12,21 @@ public class EntityProperty : IEntityProperty public Type PropertyType { get; set; } public PropertyInfo PropertyInfo { get; set; } + public bool Equals(IEntityProperty other) + { + if (other == null) + { + return false; + } + + return EntityType == other.EntityType && + IsKey == other.IsKey && + ElementName == other.ElementName && + FullPath == other.FullPath && + PropertyType == other.PropertyType && + PropertyInfo == other.PropertyInfo; + } + public object GetValue(object entity) { return PropertyInfo.GetValue(entity); diff --git a/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs b/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs index 8c6bfecd..e8616384 100644 --- a/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs +++ b/src/MongoFramework/Infrastructure/Mapping/IEntityProperty.cs @@ -3,7 +3,7 @@ namespace MongoFramework.Infrastructure.Mapping { - public interface IEntityProperty + public interface IEntityProperty : IEquatable { Type EntityType { get; } bool IsKey { get; } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertiesProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/ClassMapPropertiesProcessor.cs similarity index 91% rename from src/MongoFramework/Infrastructure/Mapping/Processors/PropertiesProcessor.cs rename to src/MongoFramework/Infrastructure/Mapping/Processors/ClassMapPropertiesProcessor.cs index 6247830c..99d11e7a 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/PropertiesProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/ClassMapPropertiesProcessor.cs @@ -7,7 +7,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { - public class PropertiesProcessor : IMappingProcessor + public class ClassMapPropertiesProcessor : IMappingProcessor { public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityRelationshipProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityRelationshipProcessor.cs index 8f56cd5f..5d81ceb8 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/EntityRelationshipProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/EntityRelationshipProcessor.cs @@ -21,7 +21,7 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) if (relationship.IsCollection) { var memberMap = classMap.MapMember(relationship.NavigationProperty.PropertyInfo); - var serializerType = typeof(EntityNavigationCollectionSerializer<>).MakeGenericType(relationship.NavigationProperty.EntityType); + var serializerType = typeof(EntityNavigationCollectionSerializer<>).MakeGenericType(relationship.EntityType); var collectionSerializer = Activator.CreateInstance(serializerType, relationship.IdProperty) as IBsonSerializer; memberMap.SetSerializer(collectionSerializer); } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs index 329c6122..b9633bea 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/HierarchyProcessor.cs @@ -8,7 +8,7 @@ public class HierarchyProcessor : IMappingProcessor public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { var entityType = definition.EntityType; - if (entityType != typeof(object) && entityType != typeof(object)) + if (entityType != typeof(object) && entityType != typeof(object) && !EntityMapping.IsRegistered(entityType.BaseType)) { EntityMapping.RegisterType(entityType.BaseType); } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs index 86c56327..f3ffd069 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/IndexProcessor.cs @@ -18,7 +18,8 @@ public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) Property = p, IndexName = a.Name, IsUnique = a.IsUnique, - SortOrder = a.SortOrder + SortOrder = a.SortOrder, + IndexPriority = a.IndexPriority }) ); } diff --git a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedPropertyProcessor.cs b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs similarity index 95% rename from src/MongoFramework/Infrastructure/Mapping/Processors/NestedPropertyProcessor.cs rename to src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs index 815d5b07..c2950ecd 100644 --- a/src/MongoFramework/Infrastructure/Mapping/Processors/NestedPropertyProcessor.cs +++ b/src/MongoFramework/Infrastructure/Mapping/Processors/NestedTypeProcessor.cs @@ -6,7 +6,7 @@ namespace MongoFramework.Infrastructure.Mapping.Processors { - public class NestedPropertyProcessor : IMappingProcessor + public class NestedTypeProcessor : IMappingProcessor { public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap) { diff --git a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs index 7c95187e..20d67dde 100644 --- a/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/EntityRelationships/EntityNavigationCollectionUnitTests.cs @@ -26,7 +26,7 @@ public void AddForeignIdWithNull() [TestMethod] public void AddForeignIdWithRightType() { - var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(StringIdModel)).GetIdProperty(); var collection = new EntityNavigationCollection(foreignProperty); collection.AddForeignId("12345678"); Assert.AreEqual(1, collection.UnloadedCount); @@ -35,7 +35,7 @@ public void AddForeignIdWithRightType() [TestMethod, ExpectedException(typeof(InvalidOperationException))] public void AddForeignIdWithWrongType() { - var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(ObjectIdIdModel)).GetIdProperty(); + var foreignProperty = EntityMapping.GetOrCreateDefinition(typeof(StringIdModel)).GetIdProperty(); var collection = new EntityNavigationCollection(foreignProperty); collection.AddForeignId(ObjectId.GenerateNewId()); } diff --git a/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs b/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs index 93559d18..70b302fc 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Linq/MongoFrameworkQueryableTests.cs @@ -2,6 +2,7 @@ using MongoDB.Driver; using MongoFramework.Infrastructure; using MongoFramework.Infrastructure.Linq; +using MongoFramework.Infrastructure.Mapping; using System.Linq; namespace MongoFramework.Tests.Infrastructure.Linq @@ -28,6 +29,8 @@ public class MongoFrameworkQueryableModel [TestMethod] public void EnumerateQueryable() { + EntityMapping.RegisterType(typeof(MongoFrameworkQueryableModel)); + var connection = TestConfiguration.GetConnection(); var collection = connection.GetDatabase().GetCollection(nameof(MongoFrameworkQueryableModel)); var underlyingQueryable = collection.AsQueryable(); @@ -47,6 +50,8 @@ public void EnumerateQueryable() [TestMethod] public void EntityProcessorsFiresOnEnumerationOfTEntity() { + EntityMapping.RegisterType(typeof(MongoFrameworkQueryableModel)); + var connection = TestConfiguration.GetConnection(); var collection = connection.GetDatabase().GetCollection(nameof(MongoFrameworkQueryableModel)); var underlyingQueryable = collection.AsQueryable(); @@ -71,6 +76,8 @@ public void EntityProcessorsFiresOnEnumerationOfTEntity() [TestMethod] public void EntityProcessorsNotFiredWhenNotTEntity() { + EntityMapping.RegisterType(typeof(MongoFrameworkQueryableModel)); + var connection = TestConfiguration.GetConnection(); var collection = connection.GetDatabase().GetCollection(nameof(MongoFrameworkQueryableModel)); var underlyingQueryable = collection.AsQueryable(); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs index 973038a0..32e4a123 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityIdProcessorTests.cs @@ -41,6 +41,7 @@ public class StringIdGeneratorTestModel public void IdMapsOnAttribute() { EntityMapping.AddMappingProcessor(new EntityIdProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); var definition = EntityMapping.RegisterType(typeof(IdByAttributeTestModel)); Assert.AreEqual("MyCustomId", definition.GetIdName()); } diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs index 4922a99b..4c259ef4 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/EntityRelationshipProcessorTests.cs @@ -107,41 +107,39 @@ public class ValidInversePropertyModel [TestMethod] public void ForeignKeyAttributeOnId() { - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); var definition = EntityMapping.RegisterType(typeof(BaseEntityModel)); var relationships = definition.Relationships; - var createdByIdProperty = definition.GetProperty("CreatedById"); - var attributeOnIdRelationship = relationships.Where(r => r.IdProperty == createdByIdProperty).FirstOrDefault(); + var attributeOnIdRelationship = relationships.Where(r => r.IdProperty.ElementName == "CreatedById").FirstOrDefault(); Assert.IsFalse(attributeOnIdRelationship.IsCollection); Assert.AreEqual(typeof(UserEntityModel), attributeOnIdRelationship.EntityType); - Assert.AreEqual(definition.GetProperty("CreatedBy"), attributeOnIdRelationship.NavigationProperty); + Assert.AreEqual("CreatedBy", attributeOnIdRelationship.NavigationProperty.ElementName); } [TestMethod] public void ForeignKeyAttributeOnNavigationProperty() { - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); var definition = EntityMapping.RegisterType(typeof(BaseEntityModel)); var relationships = definition.Relationships; - var updatedByIdProperty = definition.GetProperty("UpdatedById"); - var attributeOnIdRelationship = relationships.Where(r => r.IdProperty == updatedByIdProperty).FirstOrDefault(); + var attributeOnIdRelationship = relationships.Where(r => r.IdProperty.ElementName == "UpdatedById").FirstOrDefault(); Assert.IsFalse(attributeOnIdRelationship.IsCollection); Assert.AreEqual(typeof(UserEntityModel), attributeOnIdRelationship.EntityType); - Assert.AreEqual(definition.GetProperty("UpdatedBy"), attributeOnIdRelationship.NavigationProperty); + Assert.AreEqual("UpdatedBy", attributeOnIdRelationship.NavigationProperty.ElementName); } [TestMethod] public void IdentifyRelationshipsWithOtherIdTypes() { - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); var relationships = EntityMapping.RegisterType(typeof(BaseVariedIdModel)).Relationships; @@ -149,10 +147,10 @@ public void IdentifyRelationshipsWithOtherIdTypes() } [TestMethod] - [ExpectedExceptionPattern(typeof(InvalidOperationException), @"Unable to determine the Id property between .+ and .+\. Check the types for these properties are correct\.")] + [ExpectedExceptionPattern(typeof(InvalidOperationException), @"Unable to determine the Id property between .+ and .+\. Check the types for these properties are valid\.")] public void UnsupportedIdTypeOnRelationship() { - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); EntityMapping.RegisterType(typeof(UnsupportedIdModel)); @@ -162,7 +160,7 @@ public void UnsupportedIdTypeOnRelationship() [ExpectedExceptionPattern(typeof(InvalidOperationException), @"Can't find property .+ in .+ as indicated by the ForeignKeyAttribute.")] public void InvalidForeignKeyOnRelationship() { - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); EntityMapping.RegisterType(typeof(InvalidForeignKeyModel)); @@ -171,7 +169,7 @@ public void InvalidForeignKeyOnRelationship() [TestMethod] public void NavigationPropertiesUnmap() { - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); var definition = EntityMapping.RegisterType(typeof(BaseEntityModel)); @@ -182,7 +180,7 @@ public void NavigationPropertiesUnmap() [TestMethod] public void IdentifyCollectionRelationships() { - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); var definition = EntityMapping.RegisterType(typeof(CollectionMappingModel)); @@ -195,29 +193,38 @@ public void IdentifyCollectionRelationships() Assert.IsTrue(relationship.IsCollection); Assert.AreEqual(typeof(StringIdModel), relationship.EntityType); - Assert.AreEqual(stringIdModelDefinition.GetProperty("Id"), relationship.IdProperty); - Assert.AreEqual(definition.GetProperty("StringModelEntities"), relationship.NavigationProperty); + Assert.IsTrue(stringIdModelDefinition.GetProperty("Id").Equals(relationship.IdProperty)); + Assert.IsTrue(definition.GetProperty("StringModelEntities").Equals(relationship.NavigationProperty)); } [TestMethod] public void ValidInversePropertyMapping() { + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + var relationships = EntityMapping.RegisterType(typeof(ValidInversePropertyModel)).Relationships; Assert.IsTrue(relationships.Any(r => r.IsCollection && r.IdProperty.PropertyInfo.Name == "SecondaryId")); } [TestMethod] - [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+ in .+")] + [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+")] public void InversePropertyMappingNonExistantProperty() { + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + EntityMapping.RegisterType(typeof(InversePropertyNonExistantPropertyModel)); } [TestMethod] - [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+ in .+")] + [ExpectedExceptionPattern(typeof(InvalidOperationException), "Can't find property .+ in .+ as indicated by the InversePropertyAttribute on .+")] public void InversePropertyMappingInvalidPropertyType() { + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); + EntityMapping.AddMappingProcessor(new EntityRelationshipProcessor()); + EntityMapping.RegisterType(typeof(InversePropertyMappingInvalidPropertyTypeModel)); } } diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs index 97877172..a2bb0061 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/HierarchyProcessorTests.cs @@ -37,7 +37,7 @@ public void ParentClassIsMapped() public void AccessToInherittedProperty() { EntityMapping.AddMappingProcessor(new HierarchyProcessor()); - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); var definition = EntityMapping.RegisterType(typeof(ChildTestModel)); @@ -52,7 +52,7 @@ public void AccessToInherittedProperty() public void AccessToDeclaredProperty() { EntityMapping.AddMappingProcessor(new HierarchyProcessor()); - EntityMapping.AddMappingProcessor(new PropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); var definition = EntityMapping.RegisterType(typeof(ChildTestModel)); var mappedProperties = definition.GetAllProperties(); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs index d499801a..dc5f844e 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/MappedPropertiesProcessorTests.cs @@ -28,6 +28,7 @@ public class NotMappedPropertiesModel public void ObeysNotMappedAttribute() { EntityMapping.AddMappingProcessor(new MappedPropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); var definition = EntityMapping.RegisterType(typeof(NotMappedPropertiesModel)); Assert.IsFalse(definition.Properties.Any(p => p.ElementName == "NotMapped")); } @@ -36,6 +37,7 @@ public void ObeysNotMappedAttribute() public void ObeysColumnAttributeRemap() { EntityMapping.AddMappingProcessor(new MappedPropertiesProcessor()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); var definition = EntityMapping.RegisterType(typeof(ColumnAttributePropertyModel)); Assert.IsTrue(definition.Properties.Any(p => p.ElementName == "CustomPropertyName")); } diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedPropertyProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedTypeProcessorTests.cs similarity index 86% rename from tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedPropertyProcessorTests.cs rename to tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedTypeProcessorTests.cs index 8b6c2e0e..ee0e19c4 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedPropertyProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/NestedTypeProcessorTests.cs @@ -8,7 +8,7 @@ namespace MongoFramework.Tests.Infrastructure.Mapping.Processors { [TestClass] - public class NestedPropertyProcessorTests : MappingTestBase + public class NestedTypeProcessorTests : MappingTestBase { public class CollectionBaseModel { @@ -33,7 +33,7 @@ public class PropertyNestedModel [TestMethod] public void MapsNestedStandardPropertyModel() { - EntityMapping.AddMappingProcessor(new NestedPropertyProcessor()); + EntityMapping.AddMappingProcessor(new NestedTypeProcessor()); Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(PropertyNestedModel))); EntityMapping.RegisterType(typeof(PropertyBaseModel)); Assert.IsTrue(BsonClassMap.IsClassMapRegistered(typeof(PropertyNestedModel))); @@ -42,7 +42,7 @@ public void MapsNestedStandardPropertyModel() [TestMethod] public void MapsNestedCollectionPropertyModel() { - EntityMapping.AddMappingProcessor(new NestedPropertyProcessor()); + EntityMapping.AddMappingProcessor(new NestedTypeProcessor()); Assert.IsFalse(BsonClassMap.IsClassMapRegistered(typeof(CollectionNestedModel))); EntityMapping.RegisterType(typeof(CollectionBaseModel)); Assert.IsTrue(BsonClassMap.IsClassMapRegistered(typeof(CollectionNestedModel))); diff --git a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs index e5549bcc..f4bb67da 100644 --- a/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs +++ b/tests/MongoFramework.Tests/Infrastructure/Mapping/Processors/TypeDiscoveryProcessorTests.cs @@ -25,13 +25,11 @@ public class TypeDiscoveryAttributeModel public void TypeDiscoverySerializerWhenAttributeIsDefined() { EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); - - var serializer = BsonSerializer.LookupSerializer(); - Assert.AreNotEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.RegisterType(typeof(TypeDiscoveryAttributeModel)); - serializer = BsonSerializer.LookupSerializer(); + var serializer = BsonSerializer.LookupSerializer(); Assert.AreEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); } @@ -39,13 +37,11 @@ public void TypeDiscoverySerializerWhenAttributeIsDefined() public void NotTypeDiscoverySerializerWhenAttributeNotDefined() { EntityMapping.AddMappingProcessor(new TypeDiscoveryProcessor()); - - var serializer = BsonSerializer.LookupSerializer(); - Assert.AreNotEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition()); + EntityMapping.AddMappingProcessor(new ClassMapPropertiesProcessor()); EntityMapping.RegisterType(typeof(NoTypeDiscoveryAttributeModel)); - serializer = BsonSerializer.LookupSerializer(); + var serializer = BsonSerializer.LookupSerializer(); Assert.AreNotEqual(typeof(TypeDiscoverySerializer<>), serializer.GetType().GetGenericTypeDefinition());; } } diff --git a/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs b/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs index 05556b71..0033998c 100644 --- a/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs +++ b/tests/MongoFramework.Tests/Linq/LinqExtensionsTests.cs @@ -3,6 +3,7 @@ using MongoDB.Driver; using MongoFramework.Infrastructure; using MongoFramework.Infrastructure.Linq; +using MongoFramework.Infrastructure.Mapping; using MongoFramework.Linq; using System; using System.Linq; @@ -35,6 +36,8 @@ public class WhereIdMatchesStringModel [TestMethod] public void ValidToQuery() { + EntityMapping.RegisterType(typeof(LinqExtensionsModel)); + var connection = TestConfiguration.GetConnection(); var collection = connection.GetDatabase().GetCollection(nameof(LinqExtensionsModel)); var underlyingQueryable = collection.AsQueryable(); diff --git a/tests/MongoFramework.Tests/TestBase.cs b/tests/MongoFramework.Tests/TestBase.cs index e492d2ed..3c1488c5 100644 --- a/tests/MongoFramework.Tests/TestBase.cs +++ b/tests/MongoFramework.Tests/TestBase.cs @@ -17,6 +17,9 @@ protected static void ResetMongoDb() { ResetMongoDbDriver(); EntityMapping.RemoveAllDefinitions(); + + EntityMapping.RemoveAllMappingProcessors(); + EntityMapping.AddMappingProcessors(DefaultMappingPack.Instance.Processors); } private static void ResetMongoDbDriver()