英文:
ManyToOne mapping not working when inside an Embeddable class
问题
我正在使用Spring Boot(2.2.6.RELEASE)和JPA开发一个项目,但我遇到一个问题让我夜不能寐...
我有一个弱实体,其主键是来自父表的复合主键组成的。
+-----------------+
| BAR |
+-----------------+
| BAR_ID PK |
| NAME |
+-----------------+
|
| +-----------------+
| | FOO |
+------<+-----------------+
+------<| BAR_ID PK FK |
| | BAZ_ID PK FK |
| +-----------------+
|
+-----------------+
| BAZ |
+-----------------+
| BAZ_ID PK |
| NAME |
+-----------------+
所以我有以下的映射...
@Entity
@Table(name = "FOO")
public class Foo implements Serializable {
@Data
@Embeddable
public static class ID implements Serializable {
@ManyToOne
@JoinColumn(name="BAR_ID")
private Bar bar;
@ManyToOne
@JoinColumn(name="BAZ_ID")
private Baz baz;
}
@EmbeddedId
private ID id;
}
@Entity
@Table(name = "BAR")
@SequenceGenerator(name = "SEQ_BAR", sequenceName = "SEQ_BAR")
public class Bar implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "SEQ_BAR")
@Column(name = "BAR_ID")
private Long id;
@Column(name = "NAME")
private String name;
}
@Entity
@Table(name = "BAZ")
@SequenceGenerator(name = "SEQ_BAZ", sequenceName = "SEQ_BAZ")
public class Baz implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "SEQ_BAZ")
@Column(name = "BAZ_ID")
private Long id;
@Column(name = "NAME")
private String name;
}
以及以下的Repository接口:
@Repository
public interface FooRepository extends JpaRepository<Foo, Foo.ID> {
}
然后我尝试使用findById
fooRepository.findById(new Foo.ID(new Bar(1), new Baz(1)));
但出现了问题:
当我调用fooRepository.findById()时,尽管从数据库中检索到了行,但是Bar和Baz的ManyToOne映射却无法正常工作。这意味着无论我是执行 foo.getId().getBar().getName()
还是 foo.getId().getBaz().getName()
,Bar和Baz对象的属性 name
都是null(当然,数据库中的属性不是null)。
所以我的问题是:
这应该能够工作,对吗?
我做错了什么?
我已经尝试将fetch类型更改为EAGER,但完全没有用。
我真的非常感谢任何回复。
英文:
I am working on a project with Spring Boot (2.2.6.RELEASE) and JPA, and I am facing an issue that is bringing me nightmares...
I have a weak entity whose PK is a composite key of primary keys from parent tables.
+-----------------+
| BAR |
+-----------------+
| BAR_ID PK |
| NAME |
+-----------------+
|
| +-----------------+
| | FOO |
+------<+-----------------+
+------<| BAR_ID PK FK |
| | BAZ_ID PK FK |
| +-----------------+
|
+-----------------+
| BAZ |
+-----------------+
| BAZ_ID PK |
| NAME |
+-----------------+
So I have the following mapping...
@Entity
@Table(name = "FOO")
public class Foo implements Serializable {
@Data
@Embeddable
public static class ID implements Serializable {
@ManyToOne
@JoinColumn(name="BAR_ID")
private Bar bar;
@ManyToOne
@JoinColumn(name="BAZ_ID")
private Baz baz;
}
@EmbeddedId
private ID id;
}
@Entity
@Table(name = "BAR")
@SequenceGenerator(name = "SEQ_BAR", sequenceName = "SEQ_BAR")
public class Bar implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "SEQ_BAR")
@Column(name = "BAR_ID")
private Long id;
@Column(name = "NAME")
private String name;
}
@Entity
@Table(name = "BAZ")
@SequenceGenerator(name = "SEQ_BAZ", sequenceName = "SEQ_BAZ")
public class Baz implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "SEQ_BAZ")
@Column(name = "BAZ_ID")
private Long id;
@Column(name = "NAME")
private String name;
}
and the following Repository interface:
@Repository
public interface FooRepository extends JpaRepository<Foo, Foo.ID> {
}
then I try doing findById
fooRepository.findById(new Foo.ID(new Bar(1), new Baz(1));
and got the problem:
When I call fooRepository.findById(), although the row is fetched from database, ManyToOne mappings for Bar e Baz are not working properly. That means, whether I do foo.getId().getBar().getName()
or foo.getId().getBaz().getName()
, attribute name
is null for both Bar and Baz objects (of course, the atrributes are not null in the database).
So my questions are:
This should work, right?<br/>
What am I doing wrong?<br/>
I have already tried changing fetch type to EAGER, but that didn't work at all.
I really appreciate any replies.
答案1
得分: 0
当我打印数据库执行语句时,语句为Hibernate: select foo0_.bar_id as bar_id2_2_0_,foo0_.baz_id as baz_id1_2_0_ from foo foo0_ where foo0_.bar_id=? and foo0_.baz_id=?
。显然,JPA没有查询Bar和Baz表,因此foo.getBar().getName()
肯定为null。
您可以使用以下方法实现相同的效果。
@Entity
@Table(name = "FOO")
@Data
public class Foo implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@ManyToOne
@JoinColumn(name="BAR_ID")
private Bar bar;
@ManyToOne
@JoinColumn(name="BAZ_ID")
private Baz baz;
}
@Repository
public interface FooRepository extends JpaRepository<Foo, Long> {
Foo findByBarAndBaz(Bar bar, Baz baz);
}
像这样使用它:
Foo byId = fooRepository.findByBarAndBaz(new Bar(1L), new Baz(1L));
Bar bar = byId.getBar();
System.out.println(bar.toString());
英文:
When I print database execution statement,the statement is Hibernate: select foo0_.bar_id as bar_id2_2_0_, foo0_.baz_id as baz_id1_2_0_ from foo foo0_ where foo0_.bar_id=? and foo0_.baz_id=?
.Obviously the JPA does not query the Bar and Baz tables,so foo.getBar().getName()
certainly will be null.
You can use follow way to achieve the same effect.
@Entity
@Table(name = "FOO")
@Data
public class Foo implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@ManyToOne
@JoinColumn(name="BAR_ID")
private Bar bar;
@ManyToOne
@JoinColumn(name="BAZ_ID")
private Baz baz;
}
@Repository
public interface FooRepository extends JpaRepository<Foo, Long> {
Foo findByBarAndBaz(Bar bar, Baz baz);
}
use it like this:
Foo byId = fooRepository.findByBarAndBaz(new Bar(1L), new Baz(1L));
Bar bar = byId.getBar();
System.out.println(bar.toString());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论