Hibernate 4.2,双向@OneToOne和@Id [英] Hibernate 4.2, bidirectional @OneToOne and @Id

查看:102
本文介绍了Hibernate 4.2,双向@OneToOne和@Id的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用 OneToOne 关系将可选数据( ExtraData )添加到主类( MainItem )。
ExtraData 的所有实例都应链接到 MainItem 的实例,但不是所有 MainItem 需要一个 ExtraData 的实例。



主要关注单向关系,但似乎我需要双向关系才能将 MainItem 的更新和删除级联到 ExtraData )



我在使用 @Id ,<$ c $时遇到问题c> @OneToOne @JoinColumn 以及双向关系。



如下所示(单向):

  @Entity 
@Table(name =main_item)
公共类MainItem实现Serializable {
@Id
@Column(name =id)
private int id;

@Column(name =name)
私有字符串名称;

// + getters,setters,toString,...
}

@Entity
@Table(name =extra_data)
public class ExtraData实现Serializable {
private static final long serialVersionUID = 1L;

@Id
@OneToOne
@JoinColumn(name =item_id)
私人MainItem项目;

@Column(name =extra)
private String extra;

// + getters,setters,toString,...
}

我正在使用 hbm2ddl.auto = update ,但我也直接插入了以下数据:

  INSERT INTO main_item(id,name)VALUES(1,'Test A'); 
INSERT INTO main_item(id,name)VALUES(2,'Test B');

INSERT INTO extra_data(item_id,extra)VALUES(1,'Extra A');

通过这种单向关系,获取额外的数据及其主要项目可以正常工作:

 集合< ExtraData> extras = session.createCriteria(ExtraData.class)
.list(); (ExtraData extra:extras)
{
System.out.println(String.format(%s:%s,extra.getItem(),extra));
}

这是输出:

  Hibernate:选择this_.item_id作为item2_0_0_,this_.extra作为extra1_0_0_ from extra_data this_ 
Hibernate:选择mainitem0_.id作为id1_1_0_,mainitem0_.name作为name2_1_0_ from main_item mainitem0_ where mainitem0_.id =?
Test A:Extra A

当我添加其他 @ OneToOne 关系使关系成为双向关系,当获得 ExtraData 时,同一查询不再获取 MainItem code $ c $>
$ b

以下代码添加到 MainItem (+ get / set):

  @OneToOne(mappedBy =item,cascade = CascadeType.ALL)
private ExtraData extraData;

现在,前面的代码的输出是:

  Hibernate:select this_.item_id as item2_0_0_,this_.extra as extra1_0_0_ from extra_data this_ 
null:Extra A

我不明白为什么添加这个另外的反转关系会阻止检索 MainItem 实例。
看起来这与使用 @Id @OneToOne @JoinColumn
一起放入 ExtraData 中。
我意识到这个不适用于旧版本,但我使用的是Hibernate 4.2,它应该支持这个(虽然我不确定是否有特定的配置设置激活,但)。

使用同一列到成员使它成功,但我不知道这不会导致其他冲突:

  @Id 
@Column(name =item_id)
private int itemId;

@OneToOne
@JoinColumn(name =item_id)
私人MainItem项目;

我没有设法获得变体而不使用单独的 @Id > @OneToOne 成员,但以下变体似乎可行(至少对于该测试查询)。
用Hibernate 4.2做这件事的正确方法是什么?



  • 使用 @PrimaryKeyJoinColumn

      @Id 
    @Column(name =item_id)
    private int itemId;

    @OneToOne
    @PrimaryKeyJoinColumn
    私人MainItem项目;


  • 使用 @MapsId

      @Id 
    @Column(name =item_id)
    private int itemId;

    @OneToOne
    @MapsId
    私人MainItem项目;







<编辑:



为了澄清,我并不是真的在 MainItem code>和 ExtraData ,但我试图尽可能地分离两组数据。



<在普通的SQL中,我会这样做:

  CREATE TABLE main_item(
id INTEGER PRIMARY KEY ,
名称TEXT
);
CREATE TABLE extra_data(
item_id INTEGER PRIMARY KEY
REFERENCES main_item(id)ON UPDATE CASCADE ON DELETE CASCADE,
extra TEXT
);

这里, main_item don'不得不知道任何关于 extra_data 的内容。不管怎么处理 extra_data 都可以由其他人编码和处理,可能会晚一些。



是的,如果有人删除 extra_data 中另一行引用的 main_item 中的行, extra_data 也会被删除。



使用Hibernate,因为在生成的外键约束中没有声明级联,并且因为它似乎是从另一方的观点,似乎我需要双向关系,至少有 @OneToOne(mappedBy =item,cascade = CascadeType.ALL)private ExtraData extraData; in MainItem ,以便删除级联(否则删除 MainData 实例将失败,因为外键约束在数据库中)。



理想情况下,我希望与 ExtraData 相关的代码和数据模型依赖于在 MainItem 中的代码中,但原始的 MainIte m 不必知道 ExtraData 以及它带来的新成员。

解决方案

可选 @SecondaryTable @Table 一个选项?

  @Entity 
@Table(name =MAIN_DATA)
@SecondaryTable(name =EXTRA_DATA)
[@ org.hibernate。 annotations.Table(
applyTo =EXTRA_DATA,
fetch = FetchMode.SELECT,
optional = true)

你可以在MainItem中获得

  class MainItem {
@Column (name =extra,table =EXTRA_DATA)
private String extra;
// ...和其他字段

public void setExtraData(ExtraData extra){
this.extra = extra.getExtra();
// etc ...
}

public ExtraData getExtraData(){
ExtraData extraData = new ExtraData();

extraData.setExtra(this.extra);
//等等...
}
}

I希望它可以帮助

I'm trying to use a OneToOne relationship to add optional data (ExtraData) to a main class (MainItem). All instances of ExtraData should be linked to an instance of MainItem, but not all instances of MainItem need to have an instance of ExtraData.

(I'm primarily interested in a unidirectional relationship, but it seems that I need a bidirectional relationship to be able to cascade the updates and deletions of MainItem to ExtraData.)

I'm having trouble using @Id, @OneToOne and @JoinColumn together with the bidirectional relationship.

The classes are as follows (unidirectional):

@Entity
@Table(name = "main_item")
public class MainItem implements Serializable {
    @Id
    @Column(name = "id")
    private int id;

    @Column(name = "name")
    private String name;

    // + getters, setters, toString, ...
}

@Entity
@Table(name = "extra_data")
public class ExtraData implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @OneToOne
    @JoinColumn(name = "item_id")
    private MainItem item;

    @Column(name = "extra")
    private String extra;

    // + getters, setters, toString, ...
}

I'm using hbm2ddl.auto=update, but I've also inserted the following data directly:

INSERT INTO main_item(id, name) VALUES (1, 'Test A');
INSERT INTO main_item(id, name) VALUES (2, 'Test B');

INSERT INTO extra_data(item_id, extra) VALUES (1, 'Extra A');

With this unidirectional relationship, getting the extra data and their main items works fine:

Collection<ExtraData> extras = session.createCriteria(ExtraData.class)
        .list();
for (ExtraData extra : extras) {
    System.out.println(String.format("%s: %s", extra.getItem(), extra));
}

This is the output:

Hibernate: select this_.item_id as item2_0_0_, this_.extra as extra1_0_0_ from extra_data this_
Hibernate: select mainitem0_.id as id1_1_0_, mainitem0_.name as name2_1_0_ from main_item mainitem0_ where mainitem0_.id=?
Test A: Extra A

When I add the other @OneToOne relationship to make the relationship bidirectional, the very same query no longer gets the MainItem instances when getting the ExtraData instances.

Here is the code added to MainItem (+get/set):

@OneToOne(mappedBy = "item", cascade = CascadeType.ALL)
private ExtraData extraData;

Now, the output of the previous code is:

Hibernate: select this_.item_id as item2_0_0_, this_.extra as extra1_0_0_ from extra_data this_
null: Extra A

I don't really understand why adding this other inverted relationship prevents the MainItem instance to be retrieved. It seems it all has to do with using @Id, @OneToOne and @JoinColumn together in ExtraData. I realise this was not possible with older version, but I'm using Hibernate 4.2, which should support this (I'm not sure whether there's a specific configuration setting to activate, though).

Using the same column into to members makes it work, but I'm not sure this won't cause other conflicts:

@Id
@Column(name = "item_id")
private int itemId;

@OneToOne
@JoinColumn(name = "item_id")
private MainItem item;

I haven't managed to get a variant without using a separate @Id from the @OneToOne member, but the following variants seem to work (at least for that test query). What's the correct way to do this with Hibernate 4.2?

  • Using @PrimaryKeyJoinColumn:

    @Id
    @Column(name = "item_id")
    private int itemId;
    
    @OneToOne
    @PrimaryKeyJoinColumn
    private MainItem item;
    

  • Using @MapsId:

    @Id
    @Column(name = "item_id")
    private int itemId;
    
    @OneToOne
    @MapsId
    private MainItem item;
    


EDIT:

Just to clarify, I'm not really after a full bidirectional relationship between MainItem and ExtraData, but I'm trying to separate both sets of data as much as possible.

In plain SQL, I'd do something like this:

CREATE TABLE main_item (
    id INTEGER PRIMARY KEY,
    name TEXT
);
CREATE TABLE extra_data (
    item_id INTEGER PRIMARY KEY
        REFERENCES main_item(id) ON UPDATE CASCADE ON DELETE CASCADE,
    extra TEXT
);

Here, the concerns in main_item don't have to know anything about extra_data. Whatever has to do with extra_data could be coded and handled by someone else, possibly later.

Yes, if someone deletes a row in main_item referenced by another row in extra_data, the row in extra_data will be deleted too.

With Hibernate, because the cascading isn't declared in the generated foreign key constraint, and because it seems to be declared from the other side's perspective, it seems I need the bidirectional relationship, at least to have @OneToOne(mappedBy = "item", cascade = CascadeType.ALL) private ExtraData extraData; in MainItem, so that a deletion is cascaded (otherwise the deletion of a MainData instance will fail, because the foreign key constraint is in the database).

Ideally, I'd like the code and data model related to ExtraData to depend on the code in MainItem, but the original MainItem not to have to know about ExtraData and whatever new members it brings.

解决方案

Is optional @SecondaryTable @Table an option?

@Entity
@Table(name="MAIN_DATA")
@SecondaryTable(name="EXTRA_DATA")
[@org.hibernate.annotations.Table(
   appliesTo="EXTRA_DATA",
   fetch=FetchMode.SELECT,
   optional=true)

the you can have in MainItem

class MainItem {
  @Column(name="extra", table="EXTRA_DATA")
  private String extra;
  // ...and others field

  public void setExtraData(ExtraData extra) {
    this.extra = extra.getExtra();
    // etc...  
  }

  public ExtraData getExtraData() {
    ExtraData extraData = new ExtraData();

    extraData.setExtra(this.extra);
    // etc...  
  }
}

I hope it can help

这篇关于Hibernate 4.2,双向@OneToOne和@Id的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆