Hibernate一对一映射。仅插入外键而不是整个新行

时间:2014-10-24 04:29:59

标签: java oracle hibernate

我有RECEIPE表,CUISINE_ID是CUISINE.ID表的外键。插入新的RECIPE时可以插入,只插入CUISINE_ID,CUISINE表中没有新行。

表格结构

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 (?, ?, ?)

我的要求是没有在烹饪表中插入新行,因为recipe.cusinie_id应该只存储id。

提前致谢,

3 个答案:

答案 0 :(得分:0)

传递给DAO的Recipe对象可能包含对Cuisine对象的引用。我假设当时两个对象都与会话无关。

您对烹饪的引用的注释包含@OneToOne(cascade = CascadeType.ALL),告诉Hibernate还保存参考烹饪对象。这会产生insert into cuisine声明。

您应该删除级联注释,因为它还会导致在删除食谱时删除菜肴。

另一个解决方案是从DB加载Cuisine对象,并在保存之前在Recipe中引用它。 (但那个犯规仍然会让你删除级联)

答案 1 :(得分:0)

对于您的DAO方法,您只是传递Recipe对象的新实例,并且此对象具有您问题中提到的参数:

Recipe [id=0, name=Burger, cuisine=Cuisine [id=0, name=American]

现在在DAO方法中,您从数据库获取最大ID并使用新的id值更新Recipe实例,因此配方实例的属性将变为这样(假设数据库中的max(id))是100):

Recipe [id=101, name=Burger, cuisine=Cuisine [id=0, name=American]

您的CASCADE TYPE实体和ALL实体之间的Recipe设置为Cuisine,因此当您尝试使用以下行保存recipe实例时:

 getSession().save(recipe);

hibernate会做什么,它会尝试命中数据库以获取cuisine id的实例为0,因为recipe的实例为cuisine 1}} id0

select cuisine_.cuisine_id, cuisine_.name as name2_0_ 
    from cuisine cuisine_ 
    where
        cuisine_.cuisine_id=0

如果cuisine表的数据库中没有id作为0的记录,则hibernate假定您正在尝试在数据库中保存cuisine的新记录,因此它还会为insert生成cuisine个查询。

要避免在insert表上进行此cuisine查询,请确保您之前分配了分配给id对象的正确cuisinerecipe实例调用你的DAO方法。

答案 2 :(得分:-1)

由于您是@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();

}