首页 > 代码库 > NHibernate动态添加表

NHibernate动态添加表

NHibernate动态添加表

设置和动态扩展表差不多,添加了一个模板hbm.xml文件,用于创建动态hbm.xml,HibernateUtil无改动。

 

MappingManger添加了两个方法

 1      public static void UpdateClassMapping(DynamicTestModel dynamicModel) 2         { 3             var session = HibernateUtil.Instance.CurrentSession; 4             var fileName = "hbm_template/Template.hbm.xml"; 5             var file = File.ReadAllText(fileName); 6             file = file.Replace("@assembly", dynamicModel.GetType().Assembly.GetName().Name) 7                 .Replace("@namespace", dynamicModel.GetType().Namespace) 8                 .Replace("@class", dynamicModel.EntityName) 9                 .Replace("@table", "Dynamic_" + dynamicModel.EntityName);10 11             var xDocument = new XmlDocument();12             xDocument.LoadXml(file);13 14             var dynamicElements = xDocument.DocumentElement.GetElementsByTagName("dynamic-component");15             XmlElement dynamicElement = null;16             if (dynamicElements.Count > 0)17             {18                 dynamicElements[0].InnerXml = string.Empty;19                 dynamicElement = dynamicElements[0] as XmlElement;20             }21 22             foreach (DictionaryEntry property in dynamicModel.CustomProperties)23             {24                 var newElement = CreatePropertyElement(xDocument, dynamicElement.NamespaceURI, property);25                 dynamicElement.AppendChild(newElement);26             }27 28             Console.WriteLine(xDocument.OuterXml);29             xDocument.Save("hbm/" + dynamicModel.EntityName + ".hbm.xml");30         }31 32         private static XmlElement CreatePropertyElement(XmlDocument document, string parentNamespace, DictionaryEntry property)33         {34             var element = document.CreateElement("property", parentNamespace);35 36             element.SetAttribute("name", property.Key as string);37             element.SetAttribute("column", property.Key as string);38             element.SetAttribute("type", property.Value.GetType().Name);39             element.SetAttribute("not-null", "false");40             return element;41         }

 

CustomizableEntity类添加了一个属性

public string auto_id { get; set; }

 

创建类DynamicTestModel

 1 namespace DynamicTableTest.DynamicTable 2 { 3     public class DynamicTestModel : CustomizableEntity 4     { 5         public string EntityName { get; set; } 6  7  8         public DynamicTestModel(string entityName) 9         {10             // TODO: Complete member initialization11             this.EntityName = entityName;12         }13     }14 }

 

添加DynamicEntityTuplizer

  1 using NHibernate;  2 using NHibernate.Mapping;  3 using NHibernate.Properties;  4 using NHibernate.Proxy;  5 using NHibernate.Proxy.Map;  6 using NHibernate.Tuple;  7 using NHibernate.Tuple.Entity;  8 using System.Collections.Generic;  9  10 namespace DynamicTableTest.DynamicTable 11 { 12     public class DynamicEntityTuplizer : AbstractEntityTuplizer 13     { 14         private static readonly IInternalLogger log = LoggerProvider.LoggerFor(typeof(PocoEntityTuplizer)); 15  16         private static readonly DynamicModelAccesser Accessor = new DynamicModelAccesser(); 17         private sealed class DynamicModelMapInstantiator : IInstantiator 18         { 19             private readonly string entityName; 20             private readonly HashSet<string> isInstanceEntityNames = new HashSet<string>(); 21  22             private PersistentClass mappingInfo; 23  24             public DynamicModelMapInstantiator() 25             { 26                 entityName = null; 27             } 28  29             public DynamicModelMapInstantiator(PersistentClass mappingInfo) 30             { 31                 this.mappingInfo = mappingInfo; 32                 entityName = mappingInfo.EntityName; 33                 isInstanceEntityNames.Add(entityName); 34                 if (mappingInfo.HasSubclasses) 35                 { 36                     foreach (PersistentClass subclassInfo in mappingInfo.SubclassClosureIterator) 37                         isInstanceEntityNames.Add(subclassInfo.EntityName); 38                 } 39             } 40              41             public object Instantiate(object id) 42             { 43                 return Instantiate(); 44             } 45  46             public object Instantiate() 47             { 48                 var model = new DynamicTestModel(entityName); 49                 return model; 50             } 51  52             public bool IsInstance(object obj) 53             { 54                 var that = obj as DynamicTestModel; 55                 if (that != null) 56                 { 57                     if (entityName == null) 58                     { 59                         return true; 60                     } 61                     string type = that.EntityName; 62                     return type == null || isInstanceEntityNames.Contains(type); 63                 } 64                 else 65                 { 66                     return false; 67                 } 68             } 69         } 70  71         public DynamicEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) 72             : base(entityMetamodel, mappingInfo) 73         { 74             // NH different behavior fo NH-1587 75             Instantiator = BuildInstantiator(mappingInfo); 76         } 77  78         public override System.Type ConcreteProxyClass 79         { 80             get { return typeof(DynamicTestModel); } 81         } 82  83         public override bool IsInstrumented 84         { 85             get { return false; } 86         } 87  88         public override System.Type MappedClass 89         { 90             get { return typeof(DynamicTestModel); } 91         } 92  93         public override EntityMode EntityMode 94         { 95             get { return EntityMode.Map; } 96         } 97  98         protected override IGetter BuildPropertyGetter(NHibernate.Mapping.Property mappedProperty, PersistentClass mappedEntity) 99         {100             return BuildPropertyAccessor(mappedProperty).GetGetter(null, mappedProperty.Name);101         }102 103 104 105         private IPropertyAccessor BuildPropertyAccessor(NHibernate.Mapping.Property property)106         {107             return Accessor;108         }109 110         protected override ISetter BuildPropertySetter(NHibernate.Mapping.Property mappedProperty, PersistentClass mappedEntity)111         {112             return BuildPropertyAccessor(mappedProperty).GetSetter(null, mappedProperty.Name);113         }114 115         protected override IInstantiator BuildInstantiator(PersistentClass mappingInfo)116         {117             return new DynamicModelMapInstantiator(mappingInfo); // new DynamicMapInstantiator(mappingInfo);118         }119 120         protected override IProxyFactory BuildProxyFactory(PersistentClass mappingInfo, IGetter idGetter,121                                                                     ISetter idSetter)122         {123             IProxyFactory pf = new MapProxyFactory();124             try125             {126                 //TODO: design new lifecycle for ProxyFactory127                 pf.PostInstantiate(EntityName, null, null, null, null, null);128             }129             catch (HibernateException he)130             {131                 log.Warn("could not create proxy factory for:" + EntityName, he);132                 pf = null;133             }134             return pf;135         }136     }137 }

 

DynamicInterceptor

 1 using NHibernate; 2 using NHibernate.Mapping; 3 using System.Collections.Generic; 4  5 namespace DynamicTableTest.DynamicTable 6 { 7     public class DynamicInterceptor : EmptyInterceptor 8     { 9         private readonly string entityName;10         private readonly HashSet<string> isInstanceEntityNames = new HashSet<string>();11 12         public DynamicInterceptor()13         {14             entityName = null;15         }16 17         public DynamicInterceptor(PersistentClass mappingInfo)18         {19             entityName = mappingInfo.EntityName;20             isInstanceEntityNames.Add(entityName);21             if (mappingInfo.HasSubclasses)22             {23                 foreach (PersistentClass subclassInfo in mappingInfo.SubclassClosureIterator)24                     isInstanceEntityNames.Add(subclassInfo.EntityName);25             }26         }27 28         public override string GetEntityName(object entity)29         {30             var dynamicEntity = entity as DynamicTestModel;31             if (dynamicEntity == null) {32                 return base.GetEntityName(entity);33             }34             else35             {36                 return dynamicEntity.EntityName;37             }38         }39     }40 }

 

DynamicModelAccesser
  1 using NHibernate.Engine;  2 using NHibernate.Properties;  3 using System;  4 using System.Collections;  5 using System.Reflection;  6   7 namespace DynamicTableTest.DynamicTable  8 {  9     public class DynamicModelAccesser : IPropertyAccessor 10     { 11         private static readonly string CUSTOM_PROPERTY_NAME = "CustomProperties"; 12         private static readonly string AUTO_ID_NAME = "auto_id"; 13  14         public IGetter GetGetter(System.Type theClass, string propertyName) 15         { 16             return new DynamicGetter(propertyName); 17         } 18  19         public ISetter GetSetter(System.Type theClass, string propertyName) 20         { 21             return new DynamicSetter(propertyName); 22         } 23  24         public bool CanAccessThroughReflectionOptimizer 25         { 26             get { return false; } 27         } 28  29         [Serializable] 30         public sealed class DynamicSetter : ISetter 31         { 32             private readonly string name; 33  34             internal DynamicSetter(string name) 35             { 36                 this.name = name; 37             } 38  39             public MethodInfo Method 40             { 41                 get { return null; } 42             } 43  44             public string PropertyName 45             { 46                 get { return null; } 47             } 48  49             public void Set(object target, object value) 50             { 51                 if (CUSTOM_PROPERTY_NAME.Equals(name)) 52                 { 53                     (target as DynamicTestModel).CustomProperties = (IDictionary)value; 54                 } 55                 else if (AUTO_ID_NAME.Equals(name)) 56                 { 57                     (target as DynamicTestModel).auto_id = value as string; 58                 }
59          else
60          {
61   (target as DynamicTestModel).CustomProperties[name] = value;
62 }
63 } 64 } 65 66 [Serializable] 67 public sealed class DynamicGetter : IGetter 68 { 69 private readonly string name; 70 71 internal DynamicGetter(string name) 72 { 73 this.name = name; 74 } 75 76 public MethodInfo Method 77 { 78 get { return null; } 79 } 80 81 public object GetForInsert(object owner, IDictionary mergeMap, ISessionImplementor session) 82 { 83 return Get(owner); 84 } 85 86 public string PropertyName 87 { 88 get { return null; } 89 } 90 91 public System.Type ReturnType 92 { 93 get { return typeof(object); } 94 } 95 96 public object Get(object target) 97 { 98 if (CUSTOM_PROPERTY_NAME.Equals(name)) 99 {100 return (target as DynamicTestModel).CustomProperties;101 }102 else if (AUTO_ID_NAME.Equals(name))103 {104 return (target as DynamicTestModel).auto_id;105 }106 return (target as DynamicTestModel).CustomProperties[name];107 }108 }109 }110 }

 

模板hbm.xml

 1 <?xml version="1.0" encoding="utf-8" ?> 2 <hibernate-mapping  3   xmlns="urn:nhibernate-mapping-2.2" 4   assembly="@assembly" 5   namespace="@namespace" 6   auto-import="true"  7   default-access="property"  8   default-cascade="none"  9   default-lazy="true">10 11   <class entity-name="@class" table="@table">12     <tuplizer class="DynamicEntityTuplizer" entity-mode="dynamic-map" />13     <id name="auto_id" column="auto_id" type="string">14       <generator class="uuid.hex" />15     </id>16     <dynamic-component insert="true" name="CustomProperties" optimistic-lock="true" unique="false" update="true">17     </dynamic-component>18   </class>19 </hibernate-mapping>

 

最后是测试代码,QueryOver中where在这里会有问题,改用hql语句实现了

 1 using DynamicTableTest.DynamicTable; 2 using System; 3 using System.Linq; 4  5 namespace DynamicTableTest 6 { 7     class Program 8     { 9         static void Main(string[] args)10         {11             DynamicModelMethod();12 13             Console.Read();14         }15 16         private static void DynamicModelMethod()17         {18             var entityName = "Test_Role";19             var columnName = "Name";20             var columnRole = "Role";21             var columnCreateTime = "Create_Time";22 23             var dynamicEntity = new DynamicTestModel(entityName);24             var name = Guid.NewGuid().ToString();25             dynamicEntity.SetValueOfCustomField(columnName, name);26             dynamicEntity.SetValueOfCustomField(columnRole, 31);27             dynamicEntity.SetValueOfCustomField(columnCreateTime, DateTime.Now);28 29             MappingManager.UpdateClassMapping(dynamicEntity);30             HibernateUtil.Instance.Reset();31 32             var session = HibernateUtil.Instance.CurrentSession;33 34             var trans = session.BeginTransaction();35             try36             {37                 //add38                 var id = session.Save(entityName, dynamicEntity);39                 Console.WriteLine("first name: " + name);40 41                 //get42                 var role = (DynamicTestModel)session.Get(entityName, id);43                 var storedName = role.GetValueOfCustomField(columnName);44                 Console.WriteLine("second name: "+storedName);45 46                 //update47                 var newName = Guid.NewGuid().ToString();48                 role.SetValueOfCustomField(columnName, newName);49                 session.SaveOrUpdate(entityName, role);50 51                 //get 52                 role = (DynamicTestModel)session.Get(entityName, id);53                 storedName = role.GetValueOfCustomField(columnName);54                 Console.WriteLine("third name: " + storedName);55 56                 //delete57                 session.Delete(entityName, role);58                 role = (DynamicTestModel)session.Get(entityName, id);59                 Console.WriteLine(role == null);60                 61                 var roles = session.QueryOver<DynamicTestModel>(entityName).List();62                 foreach (var roleItem in roles)63                 {64                     Console.WriteLine(roleItem.ToString());65                 }66                 Console.WriteLine("###########################################");67                 roles = session.CreateQuery(string.Format("from {0} where {1}=‘{2}‘", entityName, columnName, "abc")).Enumerable<DynamicTestModel>().ToList();68 69                 foreach (var roleItem in roles)70                 {71                     Console.WriteLine(roleItem.ToString());72                 }73 74                 trans.Commit();75             }76             catch (Exception ex)77             {78                 trans.Rollback();79                 Console.WriteLine(ex.ToString());80             }81         }82     }83 }

Over!