1 <property name="hbm2ddl.auto">update</property>
1 <?xml version="1.0" encoding="utf-8" ?> 2 <hibernate-mapping 3 xmlns="urn:nhibernate-mapping-2.2" 4 assembly="Test" 5 namespace="Test.DynamicEntityTest" 6 auto-import="true" 7 default-access="property" 8 default-cascade="none" 9 default-lazy="true"> 10 11 <class name="Contract" table="contract"> 12 <id name="Id" column="id"> 13 <generator class="native" /> 14 </id> 15 16 <property name="Name" column="name" type="string" /> 17 18 <dynamic-component insert="true" name="CustomProperties" optimistic-lock="true" unique="false" update="true"> 19 </dynamic-component> 20 21 </class> 22 </hibernate-mapping>
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5
6 namespace Test.DynamicEntityTest
7 {
8 public class Contract : CustomizableEntity
9 {
10 public virtual int Id { get; set; }
11 public virtual string Name { get; set; }
12 }
13 }
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5
6 namespace Test.DynamicEntityTest
7 {
8 public abstract class CustomizableEntity
9 {
10 private IDictionary<string, object> customProperties;
11
12 public virtual IDictionary<string, object> CustomProperties
13 {
14 get
15 {
16 if (customProperties == null)
17 {
18 customProperties = new Dictionary<string, object>();
19 }
20 return customProperties;
21 }
22 set
23 {
24 this.customProperties = value;
25 }
26 }
27
28 public virtual object GetValueOfCustomField(string name)
29 {
30 return CustomProperties[name];
31 }
32
33 public virtual void SetValueOfCustomField(string name, object value)
34 {
35 CustomProperties[name] = value;
36 }
37 }
38 }
1 using NHibernate;
2 using NHibernate.Cfg;
3 using NHibernate.Cfg.MappingSchema;
4 using NHibernate.Mapping;
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Linq;
9 using System.Text;
10 using System.Xml;
11
12 namespace Test.DynamicEntityTest
13 {
14 public class HibernateUtil
15 {
16 private static HibernateUtil instance;
17 private Configuration configuration;
18 private ISessionFactory sessionFactory;
19 private ISession session;
20
21 public static HibernateUtil Instance
22 {
23 get
24 {
25 if (instance == null)
26 {
27 instance = new HibernateUtil();
28 }
29 return instance;
30 }
31 }
32
33 private ISessionFactory SessionFactory
34 {
35 get
36 {
37 if (sessionFactory == null)
38 {
39 var config = Configuration.Configure();
40
41 var dir = new DirectoryInfo("hbm");
42 foreach (var file in dir.GetFiles("*.hbm.xml"))
43 {
44 var typeName = file.Name.Substring(0, file.Name.IndexOf('.'));
45 var namedDocument = config.LoadMappingDocument(new XmlTextReader(file.FullName), null);
46 config.AddDeserializedMapping(namedDocument.Document, namedDocument.Name);
47 }
48
49 sessionFactory = config.BuildSessionFactory();
50 }
51 return sessionFactory;
52 }
53 }
54
55 private Configuration Configuration
56 {
57 get
58 {
59 if (configuration == null)
60 {
61 configuration = new Configuration();
62 }
63 return configuration;
64 }
65 }
66
67 public ISession CurrentSession
68 {
69 get
70 {
71 if (session == null)
72 {
73 session = SessionFactory.OpenSession();
74 }
75 return session;
76 }
77 }
78
79 public void Reset()
80 {
81 if (session != null)
82 {
83 session.Flush();
84 if (session.IsOpen)
85 {
86 session.Close();
87 }
88 }
89
90 if (sessionFactory != null)
91 {
92 sessionFactory.Close();
93 }
94
95 this.configuration = null;
96 this.sessionFactory = null;
97 this.session = null;
98 }
99
100 public PersistentClass getClassMapping(Type entityClass)
101 {
102 return Configuration.GetClassMapping(entityClass);
103 }
104 }
105 }
1 using NHibernate.Cfg;
2 using NHibernate.Mapping;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Text;
7
8 namespace Test.DynamicEntityTest
9 {
10 public class CustomizableEntityManager
11 {
12 private Component customProperties;
13 public Type EntityType { get; private set; }
14
15 public CustomizableEntityManager(Type entityType)
16 {
17 this.EntityType = entityType;
18 }
19
20 public Component CustomProperties
21 {
22 get
23 {
24 if (customProperties == null)
25 {
26 var property = PersistentClass.GetProperty("CustomProperties");
27 customProperties = (Component)property.Value;
28 }
29
30 return customProperties;
31 }
32 }
33
34 public void AddCustomFields(string[] names)
35 {
36 foreach (var name in names)
37 {
38 InnerAddCustomField(name);
39 }
40 UpdateMapping();
41 }
42
43 public void AddCustomField(string name)
44 {
45 InnerAddCustomField(name);
46 UpdateMapping();
47 }
48
49 private void InnerAddCustomField(string name)
50 {
51 var simpleValue = new SimpleValue();
52 simpleValue.AddColumn(new Column(name));
53 simpleValue.TypeName = typeof(string).Name;
54
55 var persistentClass = PersistentClass;
56 simpleValue.Table = persistentClass.Table;
57
58 var property = new Property();
59 property.Name = name;
60 property.Value = simpleValue;
61 CustomProperties.AddProperty(property);
62 }
63
64 private void UpdateMapping()
65 {
66 MappingManager.UpdateClassMapping(this);
67 HibernateUtil.Instance.Reset();
68 }
69
70 private PersistentClass PersistentClass
71 {
72 get
73 {
74 return HibernateUtil.Instance.getClassMapping(this.EntityType);
75 }
76 }
77 }
78 }
1 using NHibernate.Mapping;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Reflection;
6 using System.Text;
7 using System.Xml;
8 using System.Xml.Linq;
9
10 namespace Test.DynamicEntityTest
11 {
12 public class MappingManager
13 {
14 private static const string DYNAMIC_COMPONENT_TAG = "dynamic-component";
15
16 public static void UpdateClassMapping(CustomizableEntityManager entityManager)
17 {
18 var session = HibernateUtil.Instance.CurrentSession;
19 var entityType = entityManager.EntityType;
20 var fileName = string.Format("hbm/{0}.hbm.xml", entityType.Name);
21 var xDocument = new XmlDocument();
22 xDocument.Load(fileName);
23
24 var dynamicElements = xDocument.DocumentElement.GetElementsByTagName(DYNAMIC_COMPONENT_TAG);
25 XmlElement dynamicElement = null;
26 if (dynamicElements.Count > 0)
27 {
28 dynamicElements[0].InnerXml = string.Empty;
29 dynamicElement = dynamicElements[0] as XmlElement;
30 }
31
32 foreach (var property in entityManager.CustomProperties.PropertyIterator)
33 {
34 var newElement = CreatePropertyElement(xDocument,dynamicElement.NamespaceURI, property);
35 dynamicElement.AppendChild(newElement);
36 }
37
38 Console.WriteLine(xDocument.OuterXml);
39 xDocument.Save(fileName);
40 }
41
42 private static XmlElement CreatePropertyElement(XmlDocument document,string parentNamespace, NHibernate.Mapping.Property property)
43 {
44 var element = document.CreateElement("property", parentNamespace);
45
46 element.SetAttribute("name", property.Name);
47 element.SetAttribute("column", ((Column)property.ColumnIterator.First()).Name);
48 element.SetAttribute("type", property.Type.ReturnedClass.Name);
49 element.SetAttribute("not-null", "false");
50 return element;
51 }
52 }
53 }
1 using System;
2 using Test.DynamicEntityTest;
3
4 namespace Test
5 {
6 public class Program
7 {
8 static void Main(params string[] args)
9 {
10 CustomEntityTest();
11 Console.Read();
12 }
13
14 static void CustomEntityTest()
15 {
16 var fieldName = "email";
17 var value = "alex@test.com";
18 var session = HibernateUtil.Instance.CurrentSession;
19 var contactEntityManager = new CustomizableEntityManager(typeof(Contract));
20 contactEntityManager.AddCustomField(fieldName);
21
22 session = HibernateUtil.Instance.CurrentSession;
23 var trans = session.BeginTransaction();
24 try
25 {
26 //add
27 var contact = new Contract();
28 contact.Name = "Contact Name";
29 contact.SetValueOfCustomField(fieldName, value);
30 var id = session.Save(contact);
31
32 //get
33 contact = session.Get<Contract>(id);
34 var contactValue = contact.GetValueOfCustomField(fieldName);
35 Console.WriteLine("Value: " + contactValue);
36
37 //update
38 contact.SetValueOfCustomField(fieldName, "test@test.com");
39 session.SaveOrUpdate(contact);
40
41 //delete
42 session.Delete(contact);
43
44 trans.Commit();
45 }
46 catch (Exception ex)
47 {
48 trans.Rollback();
49 Console.WriteLine(ex.ToString());
50 }
51 }
52 }
53 }
Over!