I am exploring possible ideas when it comes to designing the one-to-one and one-to-many relationships while using Spring Data R2DBC.
As Spring Data R2DBC still do not support relationships natively there is still a need to handle those on our own (unlike Spring Data JDBC).
What I would imagine that when it comes to one-to-one mapping, the implementation could look like this:
@Table("account")
public class Account {
@Id
private Long id;
@Transient // one-to-one
private Address address;
}
@Table("address")
public class Address {
@Id
private Integer id;
}
while the database schema would be defined as follows:
--address
CREATE TABLE address
(
id SERIAL PRIMARY KEY
)
--account
CREATE TABLE account
(
id SERIAL PRIMARY KEY,
address_id INTEGER REFERENCES address(id)
)
As the Account
object is my aggregate root what I would imagine is that I am supposed to load the Address
object with it following the advice of Jens Schauder:
An aggregate is a cluster of objects that form a unit, which should always be consistent. Also, it should always get persisted (and loaded) together. source: Spring Data JDBC, References, and Aggregates
This leads me to thinking that in case of one-to-one relationships like this one I in fact should have my Account
entity defined like this:
@Table("account")
public class Account {
@Id
private Long id;
@Transient // one-to-one
private Address address;
@Column("address_id")
private Integer addressId;
}
and later on to recreate the full Account
aggregate entity with an Address
I would write something like:
@Service
public class AccountServiceImpl implements AccountService {
private final AccountRepository accountRepository;
private final AddressRepository addressRepository;
public AccountServiceImpl(AccountRepository accountRepository,
AddressRepository addressRepository) {
this.accountRepository = accountRepository;
this.addressRepository = addressRepository;
}
@Override
public Mono<Account> loadAccount(Integer id) {
return accountRepository.getAccountById(id)
.flatMap(account ->
Mono.just(account)
.zipWith(addressRepository.getAddressByAccountId(account.getAddressId()))
.map(result -> {
result.getT1().setAddress(result.getT2());
return result.getT1();
})
);
}
}
If that is not the case, how else should I handle one-to-one relationships while using Spring Data R2DBC?
I think your approach is reasonable. There are just a couple of nitpicks:
map
directly?