首页 > 代码库 > NHibernate动态扩展表

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> CustomProperties13         {14             get15             {16                 if (customProperties == null)17                 {18                     customProperties = new Dictionary<string, object>();19                 }20                 return customProperties;21             }22             set23             {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 CustomizableEntityManager11     {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 CustomProperties21         {22             get23             {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 = http://www.mamicode.com/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 =http://www.mamicode.com/ 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 PersistentClass71         {72             get73             {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.DynamicEntityTest11 {12     public class MappingManager13     {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 = http://www.mamicode.com/"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             try25             {26                 //add27                 var contact = new Contract();28                 contact.Name = "Contact Name";29                 contact.SetValueOfCustomField(fieldName, value);30                 var id = session.Save(contact);31                 32                 //get33                 contact = session.Get<Contract>(id);34                 var contactValue =http://www.mamicode.com/ contact.GetValueOfCustomField(fieldName);35                 Console.WriteLine("Value: " + contactValue);36 37                 //update38                 contact.SetValueOfCustomField(fieldName, "test@test.com");39                 session.SaveOrUpdate(contact);40 41                 //delete42                 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!