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 = "[email protected]";

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, "[email protected]");

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!

你可能感兴趣的:(Hibernate)