您的位置:首页 > 数据库

Hibernate中实体映射时的命名策略(1)

2016-09-23 17:44 316 查看
有时候在实体类映射成数据库表时,我们并不太注意生成的表和列的名称,都是使用默认的名称策略,有的是干脆不使用
@Column
注解,直接使用字段名;有的则在
@Column
注解中使用
name
属性定义自己的名称,但是有时候比如说设计一个数据库有统一前缀或者后缀,上面两种方式就不适用了,而需要统一的设计命名策略,本篇文章对这部分进行总结!

1、 历史版本中命名策略
NamingStrategy

在Hibernate的旧版本中,如果要指定应用于全局的命名策略,那么必然要涉及到
NamingStrategy
这个接口,所有想自定义命名策略的类都要直接或者间接地实现这个接口。这个接口的继承结构如下:



我们一般不直接实现
NamingStrategy
接口,因为这样我们会实现所有的接口方法,有时候这并不是必要的,所以我们一般直接继承
NamingStrategy
的实现类,比如
DefaultNamingStrategy
,这是Hibernate的默认的命名策略,或者
ImprovedNamingStrategy
使用
_
分隔字段,具体选择哪个类来继承主要是看我们自己的需求。这里我们使用Hibernate默认的命名策略
DefaultNamingStrategy
来继承。

首先我们先说明一下将要使用的三个类如下,和上一篇中使用的相同,分别是Person、Address和Direction类。

Person类

@Entity
public class Person implements Serializable{
private static final long serialVersionUID = 8849870114127659929L;

@Id
@GeneratedValue
private Long id;

@Column(nullable = false)
private String name;

@Column(nullable = false)
private Integer age;

@Embedded
@AttributeOverrides({@AttributeOverride(name="direction.latitude", column=@Column(name = "person_latitude")),
@AttributeOverride(name="direction.longitude", column = @Column(name = "person_longitude"))})
private Address address;
}


Address类:

@Embeddable
public class Address implements Serializable{
private static final long serialVersionUID = 8849870114128959929L;

@Column(nullable = false)
private String country;
@Column(length = 30)
private String province;
@Column(unique = true)
private String city;
@Column(length = 50)
private String detail;

@Embedded
private Direction direction;
}


Direction类:

@Embeddable
public class Direction implements Serializable{

@Column(nullable = false)
private Integer longitude;
private Integer latitude;
}


接着我们自定义命名策略,这里使用了Apache的common依赖包,如下:

public class EntityNamingStrategy extends DefaultNamingStrategy {
@Override
public String propertyToColumnName(String propertyName) {
String column = propertyName.replaceAll("\\.", "_");
return "C_" + column;
}

@Override
public String classToTableName(String className) {
return "T_" + StringUtils.capitalize(className);
}

@Override
public String tableName(String tableName) {
return super.tableName(tableName);
}

@Override
public String columnName(String columnName) {
return super.columnName(columnName);
}
}


下面我们首先先看一下这4个方法,基本上这4个是最常用的:

propertyToColumnName
:这个是用来使用字段属性名或者字段属性路径表达式作为参数来映射成对应的列名,这里面的关键点就是使用路径表达式,这个是在使用引用类型字段,比如说自定义类型的字段时,要映射时会使用路径表达式,就如同上面在Person类中使用Address类型字段,这是传入到该方法中参数是address.country、address.city等;

classToTableName
:这个方法就比较容易理解,就是传入对应的类的全限定类名,而不仅仅只是一个普通的类名,然后通过这个参数决定映射的表名;

tableName
:是根据在映射文档中定义的表名来修改映射的策略,由于我们基本都使用注解来映射,所以这种方式不常用;

columnName
:是根据在映射文档中定义的列名来修改映射的策略,由于我们基本都使用注解来映射,所以这种方式也不常用;

定义了上面的映射策略,我们怎么让这个自定义的类起作用呢?

如果我们使用Spring Boot来构建我们的程序,那么这个就容易多了,只需要在配置文件
application.properties
中配置
spring.jpa.hibernate.naming-strategy
为我们的自定义的命名策略
com.springboot.demo.mapping.EntityNamingStrategy
即可;

另外如果只是使用普通的web工程,那么可以使用两种方式来使我们的命名策略起作用:

通过编程,如下:

通过hibernate.cfg.xml文件配置:具体的配置开如下相关文章的第一篇,因为具体配置比较繁琐,而且也不经常用,这里就不赘述了;

Configuration cfg = new Configuration().configure();
cfg.setNamingStrategy(new EntityNamingStrategy());
StandardServiceRegistryBuilder srb = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
StandardServiceRegistry sr = srb.build();
SessionFactory factory = cfg.buildSessionFactory(sr);


了解完上面的内容和相关配置,我们就来看一下具体生成的效果如下:



我们来具体分析一下里面包含的内容和相关的问题:

首先先看看生成的表名,感觉跟我们设置的不对呀,我们的设定是
T_类名
,但是生成的确是
T_类名
字母全部小写,其实表名的生成不仅和我们的程序有关系,也和对应的数据库和操作系统有关系,由于我们使用的是MySQL数据库,在它的配置文件my.ini中有
lower_case_table_names
用于控制表名的大小写,如下在Workbench中显示:



Person中基本类型的字段映射成
C_字段名
,这是按照我们的逻辑来生成的;

Person中引用类型address的中的基本类型字段映射成
C_字段名
,字段名被”_”分隔;

Person中引用类型address中的引用类型字段分别映射成person_latitude、person_longitude,并没有按照我们自定义的生成策略去生成,这说明一个问题,我们定义的全局命名策略被
@AttributeOverrides
注解覆盖掉了,也就是说有了这个注解,我们的全局策略不起作用,这一点我们要注意,下面试验一下删除这个注解生成的表结构如下:



相关文章:

mysql运维-lower_case_table_names(大小写敏感)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息