From 04dc5c9633b75264f2b2dfc4db8f0e6368314ccd Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Mon, 22 Sep 2014 01:04:53 +0100 Subject: [PATCH 1/2] NH-3704 --- .../DynamicComponentMappingTests.cs | 37 +++++++++++++ .../DynamicComponentCustomizer.cs | 52 +++++++++++++++++++ .../PropertyContainerCustomizer.cs | 35 ++++++++++++- src/NHibernate/NHibernate.csproj | 1 + 4 files changed, 123 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs index accad2b57a1..ae83d102b0a 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Linq; using NHibernate.Cfg.MappingSchema; using NHibernate.Mapping.ByCode; @@ -21,6 +22,42 @@ public IDictionary Info } } + [Test] + public void WhenMapDynCompoByDictionaryThenMapItAndItsProperties() + { + //NH-3704 + var mapper = new ModelMapper(); + mapper.Class(map => + { + map.Id(x => x.Id, idmap => { }); + map.Component(x => x.Info, new Dictionary { { "MyInt", typeof(int) }, { "MyDate", typeof(DateTime) } }, z => { }); + }); + + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Person) }); + var hbmClass = hbmMapping.RootClasses[0]; + var hbmDynamicComponent = hbmClass.Properties.OfType().SingleOrDefault(); + hbmDynamicComponent.Should().Not.Be.Null(); + hbmDynamicComponent.Properties.Select(x => x.Name).Should().Have.SameValuesAs("MyInt", "MyDate"); + } + + [Test] + public void WhenMapPrivateDynCompoByDictionaryThenMapItAndItsProperties() + { + //NH-3704 + var mapper = new ModelMapper(); + mapper.Class(map => + { + map.Id(x => x.Id, idmap => { }); + map.Component("Info", new Dictionary { { "MyInt", typeof(int) }, { "MyDate", typeof(DateTime) } }, z => { }); + }); + + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Person) }); + var hbmClass = hbmMapping.RootClasses[0]; + var hbmDynamicComponent = hbmClass.Properties.OfType().SingleOrDefault(); + hbmDynamicComponent.Should().Not.Be.Null(); + hbmDynamicComponent.Properties.Select(x => x.Name).Should().Have.SameValuesAs("MyInt", "MyDate"); + } + [Test] public void WhenMapDynCompoThenMapItAndItsProperties() { diff --git a/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/DynamicComponentCustomizer.cs b/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/DynamicComponentCustomizer.cs index c08d14ecfd2..32656316178 100644 --- a/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/DynamicComponentCustomizer.cs +++ b/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/DynamicComponentCustomizer.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; namespace NHibernate.Mapping.ByCode.Impl.CustomizersImpl { @@ -18,6 +21,55 @@ public DynamicComponentCustomizer(IModelExplicitDeclarationsHolder explicitDecla explicitDeclarationsHolder.AddAsDynamicComponent(propertyPath.LocalMember, typeof(TComponent)); } + public DynamicComponentCustomizer(IDictionary template, IModelExplicitDeclarationsHolder explicitDeclarationsHolder, ICustomizersHolder customizersHolder, PropertyPath propertyPath) + : base(explicitDeclarationsHolder, customizersHolder, propertyPath) + { + if (propertyPath == null) + { + throw new ArgumentNullException("propertyPath"); + } + if (explicitDeclarationsHolder == null) + { + throw new ArgumentNullException("explicitDeclarationsHolder"); + } + + var componentType = this.CreateType(template); + + explicitDeclarationsHolder.AddAsDynamicComponent(propertyPath.LocalMember, componentType); + } + + private System.Type CreateType(IDictionary properties) + { + var assemblyName = new AssemblyName("MyDynamicAssembly"); + var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + var typeBuilder = moduleBuilder.DefineType("MyDynamicType", TypeAttributes.Public | TypeAttributes.Serializable); + + foreach (var property in properties) + { + var propertyBuilder = typeBuilder.DefineProperty(property.Key, PropertyAttributes.HasDefault, property.Value, null); + var getMethodBuilder = typeBuilder.DefineMethod("get_" + property.Key, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, property.Value, System.Type.EmptyTypes); + var setMethodBuilder = typeBuilder.DefineMethod("set_" + property.Key, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new System.Type[] { property.Value }); + + var getILGenerator = getMethodBuilder.GetILGenerator(); + getILGenerator.Emit(OpCodes.Ldarg_0); + getILGenerator.Emit(OpCodes.Nop); + getILGenerator.Emit(OpCodes.Ret); + + var setILGenerator = setMethodBuilder.GetILGenerator(); + setILGenerator.Emit(OpCodes.Ldarg_0); + setILGenerator.Emit(OpCodes.Ldarg_1); + setILGenerator.Emit(OpCodes.Ret); + + propertyBuilder.SetGetMethod(getMethodBuilder); + propertyBuilder.SetSetMethod(setMethodBuilder); + } + + var type = typeBuilder.CreateType(); + + return type; + } + #region IDynamicComponentMapper Members public void Access(Accessor accessor) diff --git a/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs b/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs index 4ea5ec54b80..472b6f78c43 100644 --- a/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs +++ b/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs @@ -100,7 +100,14 @@ public void Component(Expression> propert TComponent dynamicComponentTemplate, Action> mapping) where TComponent : class { - RegisterDynamicComponentMapping(property, mapping); + if (dynamicComponentTemplate is IDictionary) + { + RegisterDynamicComponentMapping(property, dynamicComponentTemplate as IDictionary, mapping); + } + else + { + RegisterDynamicComponentMapping(property, mapping); + } } protected virtual void RegisterDynamicComponentMapping(Expression> property, Action> mapping) where TComponent : class @@ -110,6 +117,22 @@ protected virtual void RegisterDynamicComponentMapping(Expression(mapping, member, memberOf); } + protected virtual void RegisterDynamicComponentMapping(Expression> property, IDictionary template, Action> mapping) where TComponent : class + { + MemberInfo member = TypeExtensions.DecodeMemberAccessExpression(property); + MemberInfo memberOf = TypeExtensions.DecodeMemberAccessExpressionOf(property); + RegisterDynamicComponentMapping(template, mapping, member, memberOf); + } + + protected void RegisterDynamicComponentMapping(IDictionary template, Action> mapping, params MemberInfo[] members) + where TComponent : class + { + foreach (var member in members) + { + mapping(new DynamicComponentCustomizer(template, explicitDeclarationsHolder, CustomizersHolder, new PropertyPath(PropertyPath, member))); + } + } + protected void RegisterDynamicComponentMapping(Action> mapping, params MemberInfo[] members) where TComponent : class { @@ -485,7 +508,15 @@ public void Component(string notVisiblePropertyOrFieldName, TCompone { MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName); MemberInfo memberOf = member.GetMemberFromReflectedType(typeof(TEntity)); - RegisterDynamicComponentMapping(mapping, member, memberOf); + + if (dynamicComponentTemplate is IDictionary) + { + RegisterDynamicComponentMapping(dynamicComponentTemplate as IDictionary, mapping, member, memberOf); + } + else + { + RegisterDynamicComponentMapping(mapping, member, memberOf); + } } public void Any(string notVisiblePropertyOrFieldName, System.Type idTypeOfMetaType, Action mapping) where TProperty : class diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 54fa348f4e2..362031d4505 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -61,6 +61,7 @@ AllRules.ruleset + 3.5 From 4f872bce39a329f5958190e9e73b3bf0648d8da8 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Wed, 26 Apr 2017 14:07:33 +1200 Subject: [PATCH 2/2] Remove dependency on SharpTestEx. To be squashed. --- .../ExplicitMappingTests/DynamicComponentMappingTests.cs | 8 ++++---- .../Impl/CustomizersImpl/PropertyContainerCustomizer.cs | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs index 67635acea89..78249339d73 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/DynamicComponentMappingTests.cs @@ -35,8 +35,8 @@ public void WhenMapDynCompoByDictionaryThenMapItAndItsProperties() var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Person) }); var hbmClass = hbmMapping.RootClasses[0]; var hbmDynamicComponent = hbmClass.Properties.OfType().SingleOrDefault(); - hbmDynamicComponent.Should().Not.Be.Null(); - hbmDynamicComponent.Properties.Select(x => x.Name).Should().Have.SameValuesAs("MyInt", "MyDate"); + Assert.That(hbmDynamicComponent, Is.Not.Null); + Assert.That(hbmDynamicComponent.Properties.Select(x => x.Name), Is.EquivalentTo(new[] { "MyInt", "MyDate" })); } [Test] @@ -53,8 +53,8 @@ public void WhenMapPrivateDynCompoByDictionaryThenMapItAndItsProperties() var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Person) }); var hbmClass = hbmMapping.RootClasses[0]; var hbmDynamicComponent = hbmClass.Properties.OfType().SingleOrDefault(); - hbmDynamicComponent.Should().Not.Be.Null(); - hbmDynamicComponent.Properties.Select(x => x.Name).Should().Have.SameValuesAs("MyInt", "MyDate"); + Assert.That(hbmDynamicComponent, Is.Not.Null); + Assert.That(hbmDynamicComponent.Properties.Select(x => x.Name), Is.EquivalentTo(new[] { "MyInt", "MyDate" })); } [Test] diff --git a/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs b/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs index 3691753d3ad..d2f031fa547 100644 --- a/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs +++ b/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs @@ -112,7 +112,7 @@ protected virtual void RegisterDynamicComponentMapping(Expression(Expression> property, IDictionary template, Action> mapping) where TComponent : class + protected virtual void RegisterDynamicComponentMapping(Expression> property, IDictionary template, Action> mapping) { MemberInfo member = TypeExtensions.DecodeMemberAccessExpression(property); MemberInfo memberOf = TypeExtensions.DecodeMemberAccessExpressionOf(property); @@ -120,7 +120,6 @@ protected virtual void RegisterDynamicComponentMapping(Expression(IDictionary template, Action> mapping, params MemberInfo[] members) - where TComponent : class { foreach (var member in members) {