在用jpa这种orm框架时,有时我们实体对象存在关联关系,但实际的业务场景可能不需要用jpa来控制数据库创建数据表之间的关联约束,这时我们就需要消除掉数据库表与表之间的外键关联。
但jpa在处理建立外键时存在一些问题,在stackoverflow上搜索了相关的jpa创建实体对象关联关系但不建立外键这一系列问题后,发现这个是jpa在处理外键时存在一定的bug,官方给出的答复是在hibernate 5.x会解决掉这个问题,但是经验证5.x的版本这个问题依旧存在。下面给出这个问题的解释以及这个问题如何解决。

下面会以techer和student对象来举例,teacher和student存在一对多关系,一个teacher关联多个student。

1.teacher与student设置外键关系

teacher和student之间通过@OneToMany和@ManyToOne建立外键关联关系
teacher:

@Entity
@Table(name = "TEACHER")
public class Teacher extends BaseDomain {
@Id()
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id; @Column
private String name; @OneToMany(mappedBy = "teacher")
private List<Student> students; //getter&setter...
}

student:

@Entity
@Table(name = "STUDENT")
public class Student extends BaseDomain { @Id()
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id; @Column
private String name; @ManyToOne
@JoinColumn(name = "tid")
private Teacher teacher; //getter&setter...
}

数据库生成表结果:

CREATE TABLE “public”.”student” (
“id” int8 DEFAULT nextval(‘student_id_seq’::regclass) NOT NULL,
“name” varchar(255) COLLATE “default”,
“teacher_id” int8,
CONSTRAINT “student_pkey” PRIMARY KEY (“id”),
CONSTRAINT “fk3y5qg5r9ewc48x7ek8lx5ua8h” FOREIGN KEY (“teacher_id”) REFERENCES “public”.”teacher” > (“id”) ON DELETE NO ACTION ON UPDATE NO ACTION
)
WITH (OIDS=FALSE)
;
ALTER TABLE “public”.”student” OWNER TO “postgres”;

可以看到设置了外键”fk3y5qg5r9ewc48x7ek8lx5ua8h” FOREIGN KEY (“teacher_id”)

2.只在student端加上@ForeignKey

student

@Entity
@Table(name = "STUDENT")
public class Student extends BaseDomain { @Id()
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id; @Column
private String name; @ManyToOne
@JoinColumn(name = "tid",foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT))
private Teacher teacher; //setter&getter
}

加上该注解之后,根据这个注解说明是可以去掉外键关联关系,但发现加上后然并卵,外键还是没有去掉。这里需要说明其中@ForeignKey的value值由如下代码所示几种情况:

/**
* Used to control the application of a constraint.
*
* @since JPA 2.1
*/
public enum ConstraintMode {
/**
* Apply the constraint.
*/
CONSTRAINT,
/**
* Do not apply the constraint.
*/
NO_CONSTRAINT,
/**
* Use the provider-defined default behavior.
*/
PROVIDER_DEFAULT
}

3.在teacher端加入@org.hibernate.annotations.ForeignKey(name = “none”)

在一的这端加上@org.hibernate.annotations.ForeignKey(name = “none”)这个被jpa废弃的注解。加上之前在student中设置的@ForeignKey(注意这个是javax.persistence包下的),可以去掉外键关联
teacher:

@Entity
@Table(name = "TEACHER")
public class Teacher extends BaseDomain {
@Id()
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id; @Column
private String name; @OneToMany(mappedBy = "teacher")
@org.hibernate.annotations.ForeignKey(name = "none")
private List<Student> students; //getter&setter...
}

结果:

CREATE TABLE “public”.”student” (
“id” int8 DEFAULT nextval(‘student_id_seq’::regclass) NOT NULL,
“createdtime” timestamp(6),
“name” varchar(255) COLLATE “default”,
“version” int4,
“tid” int8,
CONSTRAINT “student_pkey” PRIMARY KEY (“id”)
)
WITH (OIDS=FALSE)
;
ALTER TABLE “public”.”student” OWNER TO “postgres”;

可以看到student表中原来关联teacher的外键没了,说明该注解起作用。

4.需要注意的坑

1.如果teacher(1的这端)有student列表(多的这端),像这样:

@OneToMany(mappedBy = "teacher")
@org.hibernate.annotations.ForeignKey(name = "none")
private List<Student> students;

如果要去掉外键关联关系,student端也需要像在2小结提到样需要加上@JoinColumn(name = “tid”,foreignKey = @ForeignKey(name = “none”,value = ConstraintMode.NO_CONSTRAINT)),但此时你会发现其中@ForeignKey中value的值不管你设置为ConstraintMode.NO_CONSTRAINT还是ConstraintMode.CONSTRAINT,数据库都不会设置外键(这个是特么的真奇怪)。但是就是不管怎样,你就是不能不设置@ForeignKey,并且你还必须要设置其中的值不能为默认值,不然就是要生成外键。这里贴下@ForeignKey的源码:

@Target({})
@Retention(RUNTIME)
public @interface ForeignKey {
/**
* (Optional) The name of the foreign key constraint. Defaults to a provider-generated name.
*
* @return The foreign key name
*/
String name() default ""; /**
* (Optional) The foreign key constraint definition. Default is provider defined. If the value of
* disableForeignKey is true, the provider must not generate a foreign key constraint.
*
* @return The foreign key definition
*/
String foreignKeyDefinition() default ""; /**
* (Optional) Used to specify whether a foreign key constraint should be generated when schema generation is in effect.
*/
ConstraintMode value() default ConstraintMode.CONSTRAINT;
}

真的是X了狗了。。。我表示久久不能理解。。。

2.teacher(1这端)没有student列表或者student列表被@Transient所修饰,像这样:

@OneToMany(mappedBy = "teacher")
@Transient
private List<Student> students;

那么也是无论你在student端设置ConstraintMode的值,都不会设置外键.but!!!你就是不能不在student端(多的这端)设置@JoinColumn(name=”tid”,foreignKey=@ForeignKey(name=”none”,value=ConstraintMode.NO_CONSTRAINT)),否则也是会生成外键

总结

所以要使数据表中没有外键关联关系。
1.当两边都有关联关系字段,1的这端利用@org.hibernate.annotations.ForeignKey(name = “none”),多的那端在JoinColumn中加上foreignKey = @ForeignKey(name = “none”,value = ConstraintMode.NO_CONSTRAINT)

2.当只有多的那端有关联字段,一的那段没有关联字段或者关联字段被@Transient所修饰,请在多的那端在JoinColumn中加上foreignKey = @ForeignKey(name = “none”,value = ConstraintMode.NO_CONSTRAINT)

最后需要说明的是@org.hibernate.annotations.ForeignKey(name = “none”)这个注解之后可能会在之后的版本会被直接移除掉,所以更新jar包的时候需要注意下。

参考资料:
①.https://hibernate.atlassian.net/browse/HHH-8805
②.https://hibernate.atlassian.net/browse/HHH-8862

jpa无外键配置的更多相关文章

  1. 【Hibernate】无外键多表查询

    无外键多表查询时编写hql,直接使用逗号分隔表,where作为联合查询条件进行查询.查询出来的结果可为两种,List<List<Object>>或者List<Map< ...

  2. ruby -- 基础学习(二) 外键配置实现级联删除

    该系列学习基于rails4.0 数据表:admins (id, name, address), articles (id, admin_id, title) admin_id 是表articles中的 ...

  3. Springboot结合Jpa的外键使用

    当我们写项目的时候,总有些奇奇怪怪的理由,非让你连表查询,其实最好的就是什么都不连,数据库完全解耦 但我们还是要学习下Jpa怎么根据外键查询 (这里说下Jpa+springboot的感觉,刚开始就感觉 ...

  4. Kettle ETL 来进行mysql 数据同步——试验环境搭建(表中无索引,无约束,无外键连接的情况)

    今天试验了如何在Kettle的图形界面(Spoon)下面来整合来mysql 数据库中位于不同数据库中的数据表中的数据. 试验用的数据表是customers: 第三方的数据集下载地址是:http://w ...

  5. Python3-sqlalchemy-orm 联表查询-无外键关系

    #-*-coding:utf-8-*- #__author__ = "logan.xu" import sqlalchemy from sqlalchemy import crea ...

  6. peewee无外键连接

    # 参考:https://blog.csdn.net/weixin_34273479/article/details/87587183 res = Name.select(Name, User.xxx ...

  7. hibernate框架学习第四天:关联关系、外键、级联等

    一对多关联关系表 一方 多方(外键)实体类 一方:TeacherModel 添加多方的集合Set 多方StudentModel 添加一方的对象一方配置关系 name:一方模型中描述多方的集合对象名 c ...

  8. EntityFramework 外键值映射

    如果在 EF OnModelCreating 中配置了实体外键映射,也就是 SQL Server 中的 ForeignKey,那么我们在添加实体的时候,主实体的主键值会自动映射到子实体的外键值,并且这 ...

  9. SQLServer 主键、外键、唯一等约束

    主键(primary key)约束.外键(foreign key)约束.唯一(unique)约束.检查(check)约束.默认值(default)约束实例 Oracle 有如下类型的约束:NOT NU ...

随机推荐

  1. 解决问题:swiper动态加载图片后无法滑动

    原因:swiper在初始化的时候会扫描swiper-wrapper下面的swiper-slide的个数,从而完成初始化,但是由于动态加载时在初始化之后的动作,所以导致无法滑动. 解决方案 1:在动态获 ...

  2. ostream_iterator的可能实现

    当我们要输出一个容器的内容时,可以使用std::copy函数,如下: vector <string> myvector; std::copy(myvector.begin(), myvec ...

  3. Airlaunch 快捷设置代码分享

    Airlaunch 快捷设置代码分享设置:prefs:root=SETTING蜂窝网络:prefs:root=MOBILE_DATA_SETTINGS_IDWIFI:prefs:root=WIFI定位 ...

  4. 6款漂亮HTML CSS样式用户留言表单

    如今我们的网站.页面更加需要注重细节,不论是字体的样式.还是图片的分辨率清晰度都会影响到用户的访问体验和PV,以及用户以后是否会回访我们的网站/博客.如果有时间的时候,老左也会浏览和阅读相关的前端网站 ...

  5. MDK 的编译过程及文件类型全解

    MDK 的编译过程及文件类型全解 ------(在arm9的开发中,这些东西都是我们自己搞定的,但是在windows上,IDE帮我们做好了,了解这些对深入开发是很有帮助的,在有arm9开发的基础上,下 ...

  6. Joint Extraction of Entities and Relations论文解析

    1. 前言 实体和关系的联合抽取问题作为信息抽取的关键任务,其实现方法可以简单分为两类: 一类是串联抽取方法.传统的串联抽取就是首先进行实体抽取,然后进行关系识别.这种分开的方法比较容易实现,而且各个 ...

  7. java框架篇---struts实现拦截器

    Struts2的拦截器和Servlet过滤器类似.在执行Action的execute方法之前,Struts2会首先执行在struts.xml中引用的拦截器,在执行完所有引用的拦截器的intercept ...

  8. 【Web安全】越权操作——横向越权与纵向越权

    参考:http://blog.csdn.net/github_39104978/article/details/78265433 看了上面的文章,对越权操作的概念还是比较模糊,不明确实际场景. 横向越 ...

  9. Visual Studio无法导航到插入点下面的符号

    Visual Studio2017编辑器按F12无法跳转到变量所属的类定义,弹窗提示[无法导航到插入点下面的符号],如下图: 解决办法: 方法一: 清理解决方案,重新生成. 方法二: 如果以上办法不行 ...

  10. C#中的索引器

    在Java中,一般会这样使用get,set方法: class Person{ private String name; public void setName(String name){ this.n ...