Fabio: Basicly I want to change the mapping of a dynamic component because 
the database schema has changed, and do it at runtime. So I want to add 
properties to the dynamic component in a for-loop.

Barry: Good find, didn't find that link so I implemented my own version, it 
uses a template which I map by code and then I copy the template to my 
variable number of attributes. This code works in my limited case, but is 
not very general I suspect. Code is below.

modelMapper.Class<TestClass>(c =>
                              {
                                c.Table("TestClass");
                                ...
                                c.Component(x => x.Properties,
                                          new
                                              {
                                                  TEMPLATE = ""
                                              }
                                          , dc =>
                                                {
                                                    dc.Property(arg => 
arg.TEMPLATE);
                                                });
                               });

...
HbmMapping mapping = 
modelMapper.CompileMappingForAllExplicitlyAddedEntities();

var dynamicComponentMappingChanger = new 
NHibernateDynamicComponentMappingChanger();
dynamicComponentMappingChanger.ClassName = "TestClass";
dynamicComponentMappingChanger.PropertyName = "Properties";
dynamicComponentMappingChanger.AddMappingChange("MyAttribute1", "TEMPLATE");
dynamicComponentMappingChanger.AddMappingChange("MyAttribute2", "TEMPLATE");
dynamicComponentMappingChanger.AddMappingChange("MyAttribute3", "TEMPLATE");
dynamicComponentMappingChanger.ChangeMapping(mapping);

    public class NHibernateDynamicComponentMappingChanger
    {
        public string ClassName { get; set; }
        public string PropertyName { get; set; }
        private Dictionary<string, List<string>> _mappingToChange = new 
Dictionary<string, List<string>>();

        /// <summary>
        /// First string is new property name, second string is template 
that is already mapped
        /// </summary>
        public void AddMappingChange(string newPropertyName, string 
nameOfPropertyToUseAsTemplate)
        {
            _mappingToChange.Add(nameOfPropertyToUseAsTemplate, 
newPropertyName);
        }
            
        public void ChangeMapping(HbmMapping mapping)
        {
            HbmClass hbmClass = mapping.RootClasses.Single(x => x.Name == 
ClassName);
            HbmDynamicComponent dynamicComponent = (HbmDynamicComponent) 
hbmClass.Properties.Single(x => x.Name == PropertyName);

            object[] items = dynamicComponent.Items;
            List<object> result = new List<object>();

            foreach(Object o in items)
            {
                HbmProperty hbmProperty = o as HbmProperty;
                if(hbmProperty != null)
                {
                    List<string> list;
                    if(_mappingToChange.TryGetValue(hbmProperty.name, out 
list))
                    {
                        foreach(string s in list)
                        {
                            HbmProperty clone = 
ObjectCopier.Clone(hbmProperty);
                            clone.name = s;
                            result.Add(clone);
                        }
                    }
                    else
                    {
                        result.Add(hbmProperty);
                    }
                } else
                {
                    result.Add(o);
                }
            }

            dynamicComponent.Items = result.ToArray();
        }
    }


    /// <summary>
    /// Extension functions that makes it possible to have multiple values 
for a key in a Dictionary. Dictionary value type should be of type List<>
    /// </summary>
    public static class MultimapExt
    {
        public static void Add<TKey, TValue, TCollection>(
            this IDictionary<TKey, TCollection> dictionary,
            TKey key,
            TValue value
        ) where TCollection : ICollection<TValue>, new()
    {
        TCollection collection;
        if(!dictionary.TryGetValue(key, out collection))
        {
            collection = new TCollection();
            dictionary.Add(key, collection);
        }

        collection.Add(value);
    }

        public static bool Remove<TKey, TValue, TCollection>(
            this IDictionary<TKey, TCollection> dictionary,
            TKey key,
            TValue value
        ) where TCollection : ICollection<TValue>
        {
            TCollection collection;
            if(dictionary.TryGetValue(key, out collection))
            {
                bool removed = collection.Remove(value);

                if(collection.Count == 0)
                    dictionary.Remove(key);

                return removed;
            }

            return false;
        }
    }

    public static class ObjectCopier
    {
        /// <summary>
        /// Perform a deep Copy of the object.
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static T Clone<T>(T source)
        {
            if(!typeof(T).IsSerializable)
            {
                throw new ArgumentException("The type must be 
serializable.", "source");
            }

            // Don't serialize a null object, simply return the default for 
that object
            if(Object.ReferenceEquals(source, null))
            {
                return default(T);
            }

            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using(stream)
            {
                formatter.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                return (T)formatter.Deserialize(stream);
            }
        }
    }    

On Tuesday, April 3, 2012 12:15:18 AM UTC+2, barry schulz wrote:
>
> I was able to add a dynamic-component and populate that component with the 
> correct properties at runtime by using the following link as a starting 
> point.
>
>
> http://www.junasoftware.com/blog/custom-domain-using-nhibernate-dynamic-component.aspx
>  
>
> You can still use the by code configuration to setup your dynamic 
> component. Notice the anonymous type has no properties (because they are 
> not known). 
>
>     mapper.Class<Test>(map =>
>
>          {
>             map.Component("DynamicAttributes", new { },componentMap =>
>             {
>                componentMap.Access(Accessor.NoSetter); // I do not have a 
> setter
>             });
>             
>
>          });
>
>
> After you add your mappings to the Configuration, add the code seen in 
> AddMappingExtensions (from the link). You'll have to modify it based on how 
> you get your dynamic attribute metadata. 
>
> Example:
>
>          foreach (var classMapping in config.ClassMappings)
>          {
>             // only do this for the class named Test for testing...
>             if (classMapping.EntityName != "YourCoolNamepsace.Test")
>             {
>                continue;
>             }
>             var componentProperty = 
> classMapping.GetProperty("DynamicAttributes");
>             var component = (Component)componentProperty.Value;
>  
>             //foreach (TODO: get user defined attributes from somewhere)
>             {               
>
>                // CreateDynamicProperty is hard coded to work with string for 
> testing...
>
>                
> component.AddProperty(CreateDynamicProperty("SomeDynamicAttribute", 
> classMapping));
>
>                component.AddProperty(CreateDynamicProperty(
> "SomeOtherDynamicAttribute", classMapping));             }          }
>
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/nhusers/-/rXw3ONiegA4J.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/nhusers?hl=en.

Reply via email to