First, let's talk about the background. In the project that was about to be launched recently, we met a customer's requirement: The table name is dynamic and determined based on some values in the database. For example
Requirement
The primary table student has two columns of ID and class.
Then there is an example from the xxxstudentdetail table, where XXX is the class value in the student table, and the value range is not limited.
That is to say, a studentdetail table must be added for each class type.
Two technical solutions were taken into consideration in the face of requirements, but they all hit the wall.
1 On namingstrategyArticleBut the reloaded classtotablename method imports the class name instead of the object.
2. The mapping information is dynamically generated at runtime, but the sessionfactory of NH has configuration. after buildsessionfactory is obtained, the configuration cannot be changed. (I tried to use reflection to forcibly Generate mapping and insert it into each dictionary in sessionfactory. However, the workload is huge, second, I have to give up without understanding the internal structure of NH)
By the way, I have also checked whether LINQ to SQL can be implemented. After reading this discussion on msdn, I feel that I can create an abstract class to map the studentdetail table using attribute, tablename is not specified. during runtime, emit is used to generate subclass of this class to map a specific table. However, the problem is that the input parameter of the reloaded gettable method is type rather than object, and the namingstrategy route of NH is stuck in the same place.
Later, the customer accepted the hard code solution of XXX (the customer also reduced the value range of XXX from around 200 to 5, otherwise, hard code will also die ...)
As a result, the technical requirement is changed to an entity class corresponding to several mappings, So we sacrifice the entity name, the main character of today.
Entity name is the new tag that appears at the beginning of nh2.1. An instance is provided on the official website. A generic class corresponds to several mappings.
Next let's take a look at mapping.
Child. HBM. xml
Childdetail. HBM. xml <? XML version = "1.0" encoding = "UTF-8" ?>
< Hibernate-Mapping Xmlns = "Urn: nhibernate-mapping-2.2" Namespace = "Somecompany. myschool. Persistent. Model" Assembly = "Somecompany. myschool. Persistent. Model" Default-lazy = "True" >
< Joined-subclass Name = "Childdetail" Extends = "Child" Entity-name = "Year2009class1childdetail" Table = "Year2009class1childdetail" >
< Key Column = "ID" Not-Null = "True" />
< Property Name = "Name" Type = "Ansistring" Length = "32" />
< Property Name = "Enrolmentdate" Type = "System. datetime" Not-Null = "True" />
< Property Name = "Classname" Type = "Ansistring" Length = "32" Not-Null = "True" />
</ Joined-subclass >
< Joined-subclass Name = "Childdetail" Extends = "Child" Entity-name = "Year2009class2childdetail" Table = "Year2009class2childdetail" >
< Key Column = "ID" Not-Null = "True" />
< Property Name = "Name" Type = "Ansistring" Length = "32" />
< Property Name = "Enrolmentdate" Type = "System. datetime" Not-Null = "True" />
< Property Name = "Classname" Type = "Ansistring" Length = "32" Not-Null = "True" />
</ Joined-subclass >
< Joined-subclass Name = "Childdetail" Extends = "Child" Entity-name = "Year2010class1childdetail" Table = "Year2010class1childdetail" >
< Key Column = "ID" Not-Null = "True" />
< Property Name = "Name" Type = "Ansistring" Length = "32" />
< Property Name = "Enrolmentdate" Type = "System. datetime" Not-Null = "True" />
< Property Name = "Classname" Type = "Ansistring" Length = "32" Not-Null = "True" />
</ Joined-subclass >
</ Hibernate-Mapping >
We can see that the corresponding table and entity name are specified for each joined subclass. How is this entity name used? In fact, we need to create our own interceptor as follows:
Interceptor Public Class Entitynameinterceptor: emptyinterceptor
{
Public Override String Getentityname ( Object Entity)
{
VaR entitynameentity = Entity As Ientitynameentity;
Return Null = Entitynameentity ? Base . Getentityname (entity): entitynameentity. entityname;
}
}
You can call the configuration. setinterceptor method or use it as a parameter in opensession. For example
Public Isession getsession ()
{
Return Sessionfactory. opensession ( New Entitynameinterceptor ());
// Return sessionfactory. opensession ();
}
Of course, my childdetail class also needs to implement the ientitynameentity interface and return the value defined in the HBM file in the get method of the entityname attribute.
Childdetail Public Class Childdetail: Child, ientitynameentity
{
Public Virtual String Name { Get ; Set ;}
Public Virtual Datetime enrolmentdate { Get ; Set ;}
Public Virtual String Classname { Get ; Set ;}
Public virtual string entityname
{< br> Get { return string . format ( " {0} childdetail " , fullclassname) ;}< BR >}
The core implementation is as above. My colleagues can find allCode.
This article has made a lot of reference to this blog and has benefited a lot. Thank you very much. There are two more interesting points about the implementation of this blogger.
First, he uses an entity class to represent three tables with inheritance relationships. This is the opposite of a normal table to represent an inheritance tree.
Second, I also introduced the usage of dynamic component.
If you are interested, take a look.