NHibernate动态扩展表

NHibernate动态扩展属性小记

http://www.infoq.com/articles/hibernate-custom-fields 的NHibernate实现

因为动态扩展表需要修改hbm.xml文件,所以hbm.xml文件必须放在可编辑的路径中。

  • hibernate.cfg.xml中添加节点
1 <property name="hbm2ddl.auto">update</property>

 

  • 假设我有一张表Contract,hbm文件如下
 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 }

 

  • Contract类继承自CustomizeableEntity
 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 }

 

  • 我们再创建一个HibernateUtil,添加了从我们指定的目录读取hbm.xml文件
  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 }

 

  • 还有CustomEntityManager用于添加自定义属性
 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 }

 

  • 最后是MappingManager,用来修改hbm.xml文件
 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!

posted @ 2014-06-27 11:59  Alex Zhou  阅读(564)  评论(0编辑  收藏  举报