3.3.2 基本的属性和类映射

典型的Hibernate属性映射定义了JavaBeans属性名称、数据库列名以及Hibernate的类型名。它把Javabean的属性映射到表的列上。最基本的配置包含了许多可以变更和可以选择的内容。通常你可以把类型名省略。因此,当属性description使用Java的String类型的时候,Hibernate会默认使用其String类型。Hibernate使用反射机制类确定Java属性的类型。因此,下面的两种声明是等价的:

<property name=”desceiption” column=”DESCRPTION” type=”string”/>

<property name=”description” column=”DESCRIPTION”/>

当属性名字和列名相同的时候,你甚至也可以忽略它们。在这里,<column>提供了更多的弹性;它有更多可以选择的属性而且可以出现不止一次。下面的两个属性映射是等价的:

<property name=”description” column=”DESCRIPTION” type=”string”/>

<property name=”description” type=”string>

<column name=”DESCRIPTION”/>

</property>

<property>定义了特定的属性用来数据库schema的自动生成。如果你没有使用hbm2ddl工具的话,你可以忽略这些。然而,这里建议你仍然包含至少那些非空的属性,因为Hibernate可以检查这些非空的设置而无需和数据库打交道:

<property name=”initialPrice” column=”INTIAL_PRICE” not-null=”true”/>

对于非空值的检查在开发的时候非常的有用。但是它并不能代替真实的数据验证,那毕竟已成超出了Hibernate的范围。

一些属性可能并没有映射到任何的列。尤其是一些派生的属性,它们的取值往往来自SQL表达式的组合。

使用派生属性

派生属性的值通常是在运行的时候计算出来的。你可以使用公式来定义。例如,我们可以把一个totalIncludingTax属性不映射到任何数据列,它只代表了数据库所有价钱的总和:

<property name=”totalIncludingTax: formula=”TOTAL+TAX_RATE*TOTAL” type=”big_decimal”/>

当每次从数据库中取得实体的时候,给定的formula就会被计算。这个属性没有对应的column属性,也不会出现在SQL的INSERT、UPDETA或者SELECT语句中。Formulas可能和数据库表关联,调用SQL函数,或者包括SQL的子查询。

这个例子,属性item作为一个派生属性,运用一个子查询来计算所有item投标的平均值:

<property name=”averageBidAmount” formula=”(select AVG(b.AMOUNT) from BID b where b.ITEM_ID=ITEM_ID)” type=”big_decimal”/>

我们早先曾经提过,如果我们有其他的访问策略的话,可以不为POJO提供访问器方法。

属性访问策略

access属性允许你指定Hibernate如何访问POJO中的属性。默认的方法是用get/set方法。而field使用反射来直接访问示例中的变量。下面的例子并不需要get/set方法对:

<property name=”name” column=”NAME” type=”string” access=”field” />

通过访问器来访问属性被认为是最佳实践。她在领域模型和数据模型之间提供了一层抽象层。同时,它也提供了更多的灵活性,例如:子类可以重写属性的定义。

如果既不能使用访问器又不能使用直接访问的方式,你可以定义自己的访问策略,你需要重写net.sf.hibernate.property.PropertyAccessor,并在access属性中声明。

控制插入和更新

对于那些映射到列的属性来说,你可以通过insert属性来控制它们时候会出现在INSERT语句中,也可以通过update属性来控制它们是否会出现在UPDATE语句中。

下面的属性就会被写入到数据库中:

<property name=”name” column”NAME” type=”string” insert=”false” update=”false”/>

JavaBean的name属性具有只读属性。如果整个类都是只读的话,那么在类的映射中,使用immutable=”false”来设定。

另外,dynamic-insert属性告诉HIbernate是否需要在SQL_INSERT语句中包含未被修改的属性,dynamic-update属性则是是否在SQL_UPDATE中包含未被修改的属性。

<class name=”org.hibernate.auction.model.User” dynamic-insert=”true” dynamic-update=”true”>

</class>

这个属性都是类级别的设置。使它们生效会使Hibernate在运行时动态的生成SQL,而不是使用缓存的SQL。而且它只会带来很小的消耗。从另一方面说,忽略那些不需要插入的列的话能够明显的改善性能,尤其是对于那些列比较多的表来说。

使用被引用的SQL标识符

默认情况下,Hibernate并不会在生成的SQL中引用表名和列名。这使得SQL更易读,同时也允许我们利用大部分关系型数据库对于引用的标识符大写小敏感的特性。从过去到现在,特别是那些遗留系统,你会碰到学学多多奇怪的字符和空格,或者你希望强制性的大小写敏感。

如果你在映射文件中使用反引号引用了表名或者列名的话,Hibernate会在生成的SQL中也引用这个标识符。下面的例子强制Hibernate在生成SQL的时候使用引用的列名“Item Description”。Hibernate知道SQL Server需要变化,而MySQL需要'Item Description'。

<property name='description' column=”'Item Description'”/>

除了这种用反引号的方式,没有其他方法强迫Hibernate使用引用的标识符。

命名转换

你可能会经常遇到数据库表和列名强制转换的情况。Hibernate为你提供了这方面的特性:它可以保证你自动执行这些命名的标准。

假设CaveatEmptor中所有的表名都必须遵守CE_<table name>的格式。

一种解决方法就是手工的在<class>中指定table属性,在你的映射文件中定义集合属性。这种比较费时,而且容易遗忘。我们可以使用另外一种方式,实现Hibernate的NamingStrategy接口,你可以在列表3.5中看到。

List 3.5

public class CENameingStragegy implements NamingStragegy{

public String classToTableName(String className){

return tableName(StringHelper.unqualify(className).toUpperCase());

public String propertyToColumnName(String propertyName){

return propertyName.toUpperCase();

}

public String tableName(String tableName){

return 'CE_”+tableName;

}

public String columnName(String columnName){

reutrn columnName;

}

public String propertyToTableName(String className,String propertyName){

return classToName(className)+'_'+propertyToColumnName(propertyName);

}

}

classToTableName()方法被调用的时机是当<class>映射没有显式的指定一个表名的时候。propertyToColumnName()方法被调用则是没有声明列名。TableName() 和columnName()方法被调用则是其对应的名称被声明的时候。

如果我们使我们的CENamingStragegy生效的话,那么类映射的声明

<class name=”BankAccount”>

就会认为表的名字是CE_BANKACCOUNT。classToTableName()方法就会把指定的类名作为参数调用。

然而,如果表名被指定的话

<class name=”BankAccount” table=”BANK_ACCOUNT”>

那么CE_BANK_ACCOUNT就会成为表的名字。在这种情况下,BANK_ACCOUT被传递给tableName()方法。

NamingStrategy最好的地方就是其动态行为的能力。为了能够指定一个特定的命名策略,我们可以在运行时为Hibernate Configuration传递一个对象:

Configuration cfg=new Configuration();

cfg.setNamingStrategy(new CENamingStrategy());

SessionFactory sessionFactory=cfg.configure().buildSessionFactory();

这种方式允许你在同一个映射文件上有多个SessionFactory实例,每个实例都使用不同的命名策略。这种方式在多客户端安装的情况下特别的有用。

其实一种更好的方式使用SQL Schema。

SQL Schema

你可以使用hibernate.default_schema配置项指定一个默认的schema。另外一种方式在映射文件中指定schema。你可以为指定的类或者集合映射指定schema:

<hibernate-mapping>

<class name='org.hibernate.auction.model.Category' table='CATEGORY' schema='AUCTION'>

</hibernate-mapping>

当然,你也可以为整个文档声明:

<hibernate-mapping default-schema='AUCTION'>

</hibernate-mapping>

声明类名

所有CaveatEmptor程序的持久化类都声明在orghibernate.auction.model中。当然,如果你每次都需要指定如此长的包名会非常的麻烦。

让我们重新考虑一下Category类。

<?xml version=”1.0”?>

<!DOCTYPE hibernate-mapping

PUBLIC “-//Hibernate/Hibernate Mapping DTD//EN”

'http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd”>

<hibernate-mapping>

<class name='org.hibernate.auction.model.Category' table='CATEGORY'>

</class>

</hibernate-mapping>

在配置的时候,我们当然不希望每次都输入那么长的包名。因此,我们采用了另外一种方式:

<?xml version=”1.0”?>

<!DOCTYPE hibernate-mapping

PUBLIC “-//Hibernate/Hibernate Mapping DTD//EN”

'http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd”>

<hibernate-mapping package=”org.hibernate.auction.model”>

<class name='org.hibernate.auction.model.Category' table='CATEGORY'>

</class>

</hibernate-mapping>

现在所有在映射文件中的类都会自动添加声明的包名。我们将在本书中所有的映射例子使用。

如果你觉得手工写XML还是消耗了太多的时间,attribute-oriented编程可能是一个更好的选择。Hibernate映射文件能够直接使用Java代码中内置的属性来生成映射文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值