浏览 8444 次
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-05-22
Hibernate中,将对象分为两类:value type和entity type.关于这一点的详细说明,大家可以参考hibernate的refenrence。我这里只说明一点entity就是我们要操作的必须持久化的对象,一个entity 至少对应一张表(多张表的存在源于集合的引入)。而值类型有可能对应于某张表的1个或多个字段(参见component定义),hibernate为之专门定义了一个SimpleValue来Mapping. 对于一个需要持久化的对象类parent(这里为了简单起见,用父子关系中的parent来讨论)。 import java.util.*; /** * @author Administrator * * To change the template for this generated type comment go to * Window&Preferences&Java&Code Generation&Code and Comments */ public class Parent { private int id; private String name; private Set children; protected Map holidays; public Map getHolidays(){ return holidays; } public void setHolidays(Map hols){ this.holidays=hols; } public int getId(){ return id; } public void setId(int id){ this.id=id; } public Parent(){ children=new HashSet(); } public String getName(){ return name; } public void setName(String name){ this.name=name; } public Set getChildren(){ return children; } public void setChildren(Set children){ this.children=children; } public void addChild(Child c) { c.setParent(this); children.add(c); } } add(***.class)以后得所有步骤涉及最主要得类:Configuration,Binder,Mappings,RootClass,。 大家可以看一下它们的源文件,我简要说明如下: Configuration: private Map classes = new HashMap(); private Map imports = new HashMap(); private Map collections = new HashMap(); private Map tables = new HashMap(); private Map namedQueries = new HashMap(); private Map namedSqlQueries = new HashMap(); private List secondPasses = new ArrayList(); private List propertyReferences = new ArrayList(); private Interceptor interceptor = EMPTY_INTERCEPTOR; private Properties properties = Environment.getProperties(); private Map caches = new HashMap(); private NamingStrategy namingStrategy = DefaultNamingStrategy.INSTANCE; private static Log log = LogFactory.getLog(Configuration.class); classes将会被用来保存对应于entity类的映射类,在这个例子中,add(Parent.class)后,classes的key 为Parent.class,对应的value为net.sf.hibernate.mapping.RootClass for class Parent.class. 值的说明的是net.sf.hibernate.mapping.RootClass这个类。涉及它的继承体系为 PersisitentClass | | | | RootClass SubClass RootClass便是我们xml文件中对应于<class>元素定义的对象,而SubClass对应于<Subclass>节点对应的对象。 (接上Configuration)Collections用来保留所有用到的集合类,如在这个例子中,add(Parent.class)后,,collections中将有两项数据: 1)key(“org.hibernate.auction.Parent.children”)—value(net.sf.hibernate.mapping.Set实例for children); 2)key(“org.hibernate.auction.Parent.holidays”)---value(net.sf.hibernate.mapping.Map实例for holidays). Tables用来保存App中所有net.sf.hibernate.mapping.Table 实例,key为tableName(注意这里的net.sf.hibernate.mapping.Table实例是真正映射数据库中的一张表,一一对应。如上面的Parent.class会生成两个Table实例,对应”parent”和”holidays”) SecondPasses:因为collection的引入使得持久类之间有了关联关系,为了绑定并且保存对应于每一个collection而建立的net.sf.hibernate.mapping.集合类 与持久类之间,以及持久类与持久类之间的关联,hibernate使用了一个SecondPass内部类。每一个collection对应建立一个SecondPass实例。SecondPasses为以后cascade操作提供了重要信息。 Properties:保存JVM 重要环境信息以及在hibernate.properties中设定的重要属性,包括jNDI,数据库方言等等。这些信息在进行session.save等操作时,提供重要信息。 NamingStrategy用来定义从className映射到TableName等等这样的名字映射策略。 Mappings: import net.sf.hibernate.mapping.Table; /** * A collection of mappings from classes and collections to * relational database tables. (Represents a single * <tt>&hibernate-mapping&</tt> element.) * @author Gavin King */ public class Mappings { private static final Log log = LogFactory.getLog(Mappings.class); private final Map classes; private final Map collections; private final Map tables; private final Map queries; private final Map sqlqueries; private final List secondPasses; private final Map imports; private String schemaName; private String defaultCascade; private String defaultPackage; private String defaultAccess; private boolean autoImport; private final List propertyReferences; private final Map caches; private final NamingStrategy namingStrategy; Gavin的话:A collection of mappings from classes and collections to relational database tables. (Represents a single hibernate-mapping> element.已经说明了这个类的重要作用。 至于PersistentClass和RootClass,这是很重要的类,里面封装了持久entity的所有信息,源码也不是很复杂,大家可以看一下。重要信息如下: private Class mappedClass; private String discriminatorValue; private Map properties = new SequencedHashMap(); private Table table; private Class proxyInterface; private final ArrayList subclasses = new ArrayList(); private final ArrayList subclassProperties = new ArrayList(); private final ArrayList subclassTables = new ArrayList(); private boolean dynamicInsert; private boolean dynamicUpdate; private int batchSize=1; private boolean selectBeforeUpdate; private int optimisticLockMode; private java.util.Map metaAttributes; 值的说明的是:mappedClass便是我们要映射的entity类(Parent.class),大家看一下dtd中对于<class>节点的属性表,便可知道针对于<class>元素的属性都要相应设置RootClass的属性。 add(parent.class)促发步骤(一些我认为没必要说明的步骤略去): 1) 在Confugurations中。用classloader装载parent.class, 2) 由类名parent.class映射出hbm文件parent.class-àparent.hbm.xml 3) 用sax解析器读取parent.hbm.xml形成一个Document内存对象。(分支1:如果不是一个well-form文件则抛出异常) 4) 调用Binder.bindRoot(org.dom4j.Document doc,Mappings createMappings() )(值得说明的是createMappings(),这个方法位于Configuration类中,返回 封装了所有Configuation的重要集合成员的Mappings. 5) 现在指挥权到了Binder类中,bindRoot传进来的参数是一个document和封装了Configuration所有重要成员的mappings。 6) 在Binder.bindRoot中,我简要罗列以下步骤: a) Element hmNode = doc.getRootElement();(取出xml文档中的跟节点,也就是<hibernate-mapping>节点。建议大家结合看dtd定义文件,了解每个元素的属性,因为所有这些属性hibernate都要一一取出,然后设置相应model的属性,任何一个属性都是对后发操作有着深远得影响。) b) 根据<hibernate-mapping〉节点各个属性设置mappings的属性。 c) Iterator nodes = hmNode.elementIterator("class");(这里要遍历XML文件中定义的所有<class>元素,他们的每一个都是一个rootClass。) d) 进入对<class>元素的循环遍历。 d-1) Element n = (Element) nodes.next(); d-2) RootClass rootclass = new RootClass(); d-3) Binder.bindRootClass(n, rootclass, mappings); bindRootClass(Element node, RootClass model, Mappings mappings)是Binder类得核心方法,顾名思义,就是对<class>元素的Bind动作,这个bind包括对<class>元素属性的bind,还包括class元素所含所有得子元素的bind,因为篇幅所限,其具体方法动作我会在以后文档中给出详细说明。我这里简要概括一下方法步骤: d-3-1)Binder.bindClass(Element node, PersistentClass model, Mappings mapping) 。bindClass方法是仅仅对<class>节点本身以及一些属性的绑定动作,并不包括<class〉子元素的绑定,而且关心的属性也不是全部。主要根据<class>元素的”name”属性找出entity class,然后调用RootClass.setMappedClass(parent.calss);接下来就是根据class元素的其中一些属性设置初始化rootclass。 d-3-2) Attribute schemaNode = node.attribute("schema"); String schema = schemaNode==null ? mappings.getSchemaName() : schemaNode.getValue(); Table table = mappings.addTable( schema, getClassTableName(model, node, mappings) ); model.setTable(table); 这里主要根据属性生成Table实例,注意这里的net.sf.hibernate.mapping.Table实例仅仅设置了tableName 和schema而已,别的属性并没有初始化。需要在下面的步骤中进行更多的设置。 d-3-3)根据<class>元素的剩余属性对rootClass进行设置。 d-3-4)对<class>的所有子元素进行遍历,在这个循环遍历中,hibernate仅仅注意这样跟初始化RootClass有重要影响的子元素及元素的所有属性( (cache|jcs-cache),(id|composite-id),discriminator, (version|timestamp)),hibernate必须根据这些重要元素的设置对RootClass以及Mappings进行bind。 d-3-5) model.createPrimaryKey(); 在这一步,根据d-3-4)中对<id>节点生成的Identifier,设置PrimaryKey。 d-3-6) propertiesFromXML(node, model, mappings); Binder. propertiesFromXML(Element node, PersistentClass model, Mappings mappings)也是一个重要方法。我觉得有必要深究一下。详细文档我也会在以后文档中给出。参阅源码,大家可以看出它的逻辑是相当清晰的。就是对<set><Map><property><many-to-one>等等子元素进行bind。 e) 进入对< subclass><joined-subclass>< query>< sql-query>等等的遍历处理。 f) 。。。。 g) 返回。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-05-22
我是初学者,刚开始看到.add(*.class)时,想看一下源代码,无赖自己hibernate
及综合素质太差,没看出个所以然,今天楼主却给写出来了!谢谢楼主! 不过我现在仍然似懂非懂,文章收藏先!等一段时间后再来研究。 |
|
返回顶楼 | |