英文:
JPA Hibertane unidirectional one-to-one with shared primary key save parent first NO REVERSE
问题
我一直在互联网上寻找答案,但对我没有任何帮助。有许多类似案例的主题,但具体细节有所不同,使它们对我无用。
因此,我有两个表:t_item 和 t_item_info:
t_item 表中的 item_id 字段引用了 t_item_info 表中的 id 字段。我正在使用 MySQL 数据库,t_item 表中的 id 列是自动递增的。
我需要以特定方式进行单向一对一映射。以下是我的类:
@Entity
@Table(name = "t_item")
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "item_id")
private ItemInfo info;
}
@Entity
@Table(name = "t_item_info")
public class ItemInfo {
@Id
private Long itemId;
private String descr;
}
所以关键是,我需要Item对象引用ItemInfo对象。不是另一种方式!
Item -> ItemInfo --是
Item <- ItemInfo --否
另一件事是,我需要父(Item)的 id 成为子(ItemInfo)的 id。
例如,我创建了一个 id 为 null 的 Item 对象,并将其 info 字段设置为也具有 null id 字段的 ItemInfo 对象。就像这样:
{
"id": null,
"name": "Some name",
"info": {
"itemId": null,
"descr": "some descr"
}
}
然后当 Item 对象持久化时,Hibernate 应该为父(Item)对象生成 id,并将其设置为子(ItemInfo)的 itemId 字段。
我一直在尝试使用不同的 Hibernate 注解来实现这一点,并且我注意到无论我多么努力,Hibernate 似乎总是试图首先持久化子对象。当我打开 SQL 日志记录时,我在日志中注意到了这一点。insert into t_item_info 总是首先执行(并因为 id 为 null 而失败 :D)
所以问题是:是否可能实现这一点,如果是,我应该在我的代码中做哪些更改。
我希望我的贫乏的解释对您有所帮助。
英文:
I'v been searching internet for answer, but nothing was working for me. There is a lot of topics with similar cases but specific details are different in a way that make them unusable for me.
So I have two tables: t_item and t_item_info:
item_id field from t_item_info table references id field from t_item table. I'm using mysql db and id column form t_item is auto incremented
I need to make unidirectional one-to-one mapping in a specific way. Here are my classes:
@Entity
@Table(name = "t_item")
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "item_id")
private ItemInfo info;
}
And other one
@Entity
@Table(name = "t_item_info")
public class ItemInfo {
@Id
private Long itemId;
private String descr;
}
So the point is that i need Item object to have a reference to ItemInfo object. NOT The other way!
Item -> ItemInfo --YES
Item <- ItemInfo --NO
The other thing is that i need parent (Item) id to become id for a child (ItemInfo)
For example I create Item object with null id and set it's info field with ItemInfo object which also have null id field. Like this:
{
"id": null,
"name": "Some name",
"info": {
"itemId": null,
"descr": "some descr"
}
}
Then when Item object persists hibernate should generate id for parent(Item) object and set it as itemId field for child(ItemInfo).
I have been trying to achieve this with different hibernate annotations and I noticed that no matter how hard I tried Hibernate always seems to try to persist child object first. I noticed it in the logs when I turned sql logging on. insert into t_item_info always goes first (and dies because of null id :D)
So the question is: Is it even possible to achieve this and if so what should I change in my code to do so
I hope that what I'm trying to ask makes sens to you given my poor explanations =)
答案1
得分: 2
为什么人们总是坚持在一对一关联中,子对象表应该是带有外键的那个,这对我来说是难以理解的。
无论如何,作为一种解决方法,由于两个对象共享“id”,并且关联是非可选的,你可以同样为子对象声明自动生成的键:
@Entity
@Table(name = "t_item_info")
public class ItemInfo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long itemId;
private String descr;
}
然后在父对象上使用 @MapsId
:
@Entity
@Table(name = "t_item")
public class Item {
@Id
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "id")
@MapsId
private ItemInfo info;
}
请注意,这种方法在某种程度上会欺骗 Hibernate,使其认为应该将Item
对象视为子对象。你已经被警告了。
英文:
Why people always insist the child object table in one-to-one associations should be the one with the foreign key is beyond me.
Anyway, as a workaround, since both objects share the id
and the association is non-optional, you might as well declare the autogenerated key for the child object:
@Entity
@Table(name = "t_item_info")
public class ItemInfo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long itemId;
private String descr;
}
and then use @MapsId
for the parent:
@Entity
@Table(name = "t_item")
public class Item {
@Id
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "id")
@MapsId
private ItemInfo info;
}
Note that this approach, will, in a sense, fool Hibernate into thinking it is the Item
that should be treated as the child object. You have been warned.
答案2
得分: 1
虽然这里有一个被接受的答案,但在我看来 `@Secondary` 表可能是一个更好和更方便的解决方案:你可以在数据库级别上有2个表,但我没有看到任何理由需要将这个事实暴露给任何客户端代码。似乎没有太多好处?以下提供了一个更简单的API。
实体:
@Entity
@Table(name = "t_item")
@SecondaryTable(name = "t_item_info", pkJoinColumns={
@PrimaryKeyJoinColumn(name="id", referencedColumnName="item_id")})
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Column(name = "description", table= "t_item_info")
private String description;
}
API:
{
"id": null,
"name": "某个名称",
"descr": "一些描述"
}
英文:
While there is an accepted answer here it looks to me like @Secondary
table would be a better and more convenient solution: you may have 2 tables at the database level but I do not see any reason that that fact needs be exposed to any client code. There does not seem to be a lot of benefit to that? The following gives you a simpler API.
Entity:
@Entity
@Table(name = "t_item")
@SecondaryTable("t_item_info", pkJoinColumns={
@PrimaryKeyJoinColumn(name="id", referencedColumnName="item_id")})
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Colulumn(name = "description", table= "t_item_info"")
private String description;
}
API:
{
"id": null,
"name": "Some name",
"descr": "some descr"
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论