Reputation: 5241
we have linked 2 entities with bi-directional @ManyToOne relation like this:
@Entity
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "foo")
private Set<Bar> bars;
}
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Bar {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "foo_id")
private Foo foo;
}
When I create Foo entity and Bar entity, and try to set created Foo into Bar, change is not reflected on other side.
Here is code from my integration test:
Foo foo = fooRepository.save(Foo.builder()...build());
Bar bar = new Bar();
bar.setFoo(foo);
bar.set...();
barRepository.save(bar);
Foo updatedFoo = fooRepository.findById(foo.getId()).get();
List<Bar> bars = updatedFoo.getBars(); // this is null
I have no idea why bars from fetched foo is null. When I try fetch given Bar from repository I can see saved Foo on this side.
Upvotes: 0
Views: 75
Reputation: 8203
bar.setFoo()
which you did, the database will be updated with the relationship changes. So your database is correctfoo
will only reflect what is in the database if you manually set it, or you force it to be refreshed or reloaded eg entityManager.refresh(foo)
Notes
In a transactional session, every call to repository does not translate to database call. Since hibernate all ready has foo
as a managed
entity in line1,
when you call, fooRepository.findById(foo.getId()).get();
JPA does not issue a select statement. If you search about Transactional write-behind
and Repeatable Read
, you can find out about this more
Foo foo = fooRepository.save(Foo.builder()...build());
- foo
becomes managed entity, due to Repeatable read
guarantee, JPA will return the same foo
for all subsequent retrievals of foo
.
It does not even go to database if you call fooRepository.findById(fooId)
after the save.
barRepository.save(bar);
- bar
also becomes managed
Both foo
and bar
are managed entities, but foo says I don't have any bar
s and bar says I know a foo
as you didn't set foo.getbars().add(bar)
. This is incorrect in memory as you have to explicitly set both side of relationships.
If you complete the current transactional method
without adding the bar to foo, and then if you call fooRepository.findById(fooId)
in another transactional, it will show you it get foo and bars.
More references
Upvotes: 0
Reputation: 311
have you try adding cascade to your mappings,
@OneToMany(fetch = FetchType.LAZY, mappedBy = "foo",cascade= CascadeType.ALL)
private Set<Bar> bars;
@ManyToOne(cascade= CascadeType.ALL)
@JoinColumn(name = "foo_id")
private Foo foo;
and your code:
Foo foo = fooRepository.save(Foo.builder()...build());
Bar bar = new Bar();
bar.setFoo(foo);
bar.set...();
barRepository.save(bar);
barRepository.save(bar) will not persist the foo.
when you add cascade it will persist both the entities or you need to manually save the foo entity with fooRepository.
Upvotes: 1