JPA Hibertane unidirectional one-to-one with shared primary key save parent first NO REVERSE

huangapple go评论78阅读模式
英文:

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:

JPA Hibertane unidirectional one-to-one with shared primary key save parent first NO REVERSE

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 = &quot;t_item&quot;)
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 = &quot;id&quot;, referencedColumnName = &quot;item_id&quot;)
    private ItemInfo info;
}

And other one

@Entity
@Table(name = &quot;t_item_info&quot;)
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 -&gt; ItemInfo   --YES
Item &lt;- 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:

{
  &quot;id&quot;: null,
  &quot;name&quot;: &quot;Some name&quot;,
  &quot;info&quot;: {
    &quot;itemId&quot;: null,
    &quot;descr&quot;: &quot;some descr&quot;
  }
}

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 = &quot;t_item_info&quot;)
public class ItemInfo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long itemId;

    private String descr;
}

and then use @MapsId for the parent:

@Entity
@Table(name = &quot;t_item&quot;)
public class Item {
    @Id
    private Long id;

    private String name;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = &quot;id&quot;)
    @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 = &quot;t_item&quot;)
@SecondaryTable(&quot;t_item_info&quot;,  pkJoinColumns={
        @PrimaryKeyJoinColumn(name=&quot;id&quot;, referencedColumnName=&quot;item_id&quot;)})
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Colulumn(name = &quot;description&quot;, table= &quot;t_item_info&quot;&quot;)
    private String description;
}

API:

{
  &quot;id&quot;: null,
  &quot;name&quot;: &quot;Some name&quot;,
  &quot;descr&quot;: &quot;some descr&quot;
}

huangapple
  • 本文由 发表于 2020年7月27日 02:09:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/63103901.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定