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 initialization
11             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             try
125             {
126                 //TODO: design new lifecycle for ProxyFactory
127                 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             else
35             {
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             try
36             {
37                 //add
38                 var id = session.Save(entityName, dynamicEntity);
39                 Console.WriteLine("first name: " + name);
40 
41                 //get
42                 var role = (DynamicTestModel)session.Get(entityName, id);
43                 var storedName = role.GetValueOfCustomField(columnName);
44                 Console.WriteLine("second name: "+storedName);
45 
46                 //update
47                 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                 //delete
57                 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!

posted @ 2014-06-27 12:20  Alex Zhou  阅读(632)  评论(0编辑  收藏  举报