Java 休眠一对一映射。仅插入外键,而不是整个新行
我有RECEIPE table和Cookie_ID是Cookie.ID table的外键。插入新菜谱时可以,只插入烹饪ID,烹饪表中没有新行 表结构Java 休眠一对一映射。仅插入外键,而不是整个新行,java,oracle,hibernate,Java,Oracle,Hibernate,我有RECEIPE table和Cookie_ID是Cookie.ID table的外键。插入新菜谱时可以,只插入烹饪ID,烹饪表中没有新行 表结构 create table CUISINE(cuisine_id number primary key, name varchar2(20)); create table RECIPE(id number primary key, name varchar2(25) not null,
create table CUISINE(cuisine_id number primary key, name varchar2(20));
create table RECIPE(id number primary key,
name varchar2(25) not null,
cuisine_id number,
constraint cuisine_fk foreign key (cuisine_id) references
cuisine(cuisine_id));
类映射:
@Entity
@Table(name = "cuisine")
public class Cuisine {
@Id
@Column(name = "cuisine_id")
private int id;
@Column(name = "name")
@NotBlank(message = "You can not leave this empty.")
@NotNull(message = "You can not leave this empty.")
private String name;
@Entity
@Table(name = "recipe")
public class Recipe {
@Id
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "cuisine_id")
private Cuisine cuisine;
一旦我从JSP页面中获得了正在填充的RECEIPE类,我就会从modelAttribute中获得以下内容
Recipe [id=0, name=Burger, cuisine=Cuisine [id=0, name=American]
DAO代码是
public void addRecipe(Recipe recipe) {
String hql = "select max(id) from Recipe";
Integer id = ((Integer) getSession().createQuery(hql).uniqueResult()) + 1;
recipe.setId(id);
getSession().save(recipe);
}
从日志中,我可以看到插入了以下内容:
Hibernate: insert into cuisine (name, cuisine_id) values (?, ?)
Hibernate: insert into recipe (cuisine_id, name, id) values (?, ?, ?)
我的要求是烹饪表中没有新的一行作为菜谱插入。cusinie_id应该只存储id
提前感谢,传递给DAO的Recipe对象可能包含对Cuisine对象的引用。我假设这两个对象当时都没有与会话关联 您对美食的引用的注释包含一个
@OneToOne(cascade=CascadeType.ALL)
,告诉Hibernate也保存引用对象。这将导致您的插入到语句中
您可能应该删除级联注释,因为它也会导致在您删除菜谱时删除烹饪
另一种解决方案是从DB加载烹饪对象,并在保存之前在菜谱中引用它。(但这仍然需要删除级联)因为您是@OneToOne(cascade=CascadeType.ALL)
我们的代码告诉您,首先必须保存引用,然后保存实际的表值
我在这里看到,您正在一次性保存整个交易
这段代码在DAO实现中可能会有所帮助
public void addRecipe(Recipe recipe) {
String hql = "select max(id) from Recipe";
getSession().beginTransaction();
Integer id = ((Integer) getSession().createQuery(hql).uniqueResult()) + 1;
recipe.setId(id);
getSession().save(recipe.getCuisine);
getSession().save(recipe);
getSession().getTransaction().commmit();
}
向DAO方法传递的只是Recipe
对象的一个新实例,该对象具有问题中提到的参数:
Recipe [id=0, name=Burger, cuisine=Cuisine [id=0, name=American]
现在,在DAO方法中,您将从数据库获取最大id,并使用新的id值更新您的配方
实例,因此配方实例的属性将如下所示(假设数据库中的最大id为100):
您的配方
实体和烹饪
实体之间的级联类型
设置为全部
,因此当您尝试使用以下行保存配方
实例时:
getSession().save(recipe);
hibernate将要做的是,它将尝试点击数据库,以获得一个烹饪的实例,该实例的id
为0
,因为您的食谱有一个烹饪的实例,其id
为0
select cuisine_.cuisine_id, cuisine_.name as name2_0_
from cuisine cuisine_
where
cuisine_.cuisine_id=0
如果数据库中没有id为0
的courine
表的记录,则hibernate假定您正在尝试在数据库中保存courine
的新记录,因此它也将为courine
生成insert
查询
为了避免在courine
表上执行此insert
查询,请确保在调用DAO方法之前,将分配给recipe
对象的id
实例分配给courine
对象。我没有理解您所说的“两个对象当时都与会话不关联”的意思。由于Recipe类具有声明“private Cuisine”,因此在对“Recipe”类进行查询时,这两个对象都将被选中。当您想要存储一个新的配方(即您不只是从数据库中读取的配方)时,可以调用addRecipe()。在session.save(recipe)之前,recipe只是一个数据对象,会话对此一无所知。这就是我所说的“与会议无关”的意思。食谱还引用了一个烹饪对象。我假设这个对象也不是从数据库读取的,会话也不知道关于这个对象的任何信息。级联注释将导致hibernate也保存该对象。谢谢您的建议。删除OneTONE注释中的级联,使代码可执行。但我遇到了另一个与验证相关的例外情况。。我还在琢磨如何解决这个问题。你的代码显式地做了他的代码隐式地做的事情:存储一个对象。这正是他想要避免的。在DAO方法中进行显式事务处理也不是一个好主意,由于该方法可能是更大事务的一部分。我的坏消息是,由于引用表不影响显式代码,因此我认为可能会有帮助,对于事务,我猜测数据不会保存,因为会话可能需要更多操作,这就是我添加transaction()的原因。commit().没有在美食中插入新的一行,您可以在哪里获得美食id?您先插入烹饪吗?抱歉,我尝试过,但代码无法执行。它在courine.Name处给出了验证错误。(使用多个注释来明确我的注释)我保留了@OneToOne(cascade=CascadeType.ALL)。正如您建议的那样,Hibernate在烹饪上运行select查询。但在日志中,在运行insert语句后,它给出了“javax.validation.ConstraintViolationException:在组[javax.validation.groups.Default]的更新期间类[com.recipe.tables.courity]的验证失败,]约束冲突列表:[”@Sandeep,不清楚您尝试了什么,以及您现在遇到了什么异常。请使用您尝试过的确切代码更新您的问题,并完成您现在遇到的异常的stacktrace。
select cuisine_.cuisine_id, cuisine_.name as name2_0_
from cuisine cuisine_
where
cuisine_.cuisine_id=0