6

I am trying to replicate some functionality that I was using in Spring Data JPA in the new reactive Data r2dbc. I am aware that r2dbc is not a full-fledged ORM but wanted to understand as what could be the best way to replicate the below scenario in r2dbc:

public class Doctor extends BaseModel {

    //other fields and id

    @NotNull
    @Enumerated(EnumType.STRING)
    @ElementCollection(fetch = FetchType.LAZY, targetClass = Language.class)
    @CollectionTable(name = "doctor_language",
        joinColumns = @JoinColumn(name = "doctor_id"))
    @Column(name = "language")
    private List<Language> languages = new ArrayList<>();


    @OneToMany(fetch = FetchType.LAZY, targetEntity = DoctorHealthProvider.class, mappedBy = 
        "doctor")
    private List<DoctorHealthProvider> providers = new ArrayList<>();

    // other fields
}

A simple findById call on DoctorRepository (which extends JpaRepository) will give me doctor object with list of languages from doctor_language table and list of health providers from health_provider table if I use Spring Data JPA

I was reading about projections but couldn't seem to figure out the best way to implement the above in Reactive Spring. Any help/guidelines/direction is appreciated.

Thanks

abstractKarshit
  • 1,355
  • 2
  • 16
  • 34
  • 2
    Currently R2DBC do not allow auto relational loading like this. – nicholasnet Jul 01 '20 at 01:48
  • Not very good solution, but you can use special repository fragment with one method which will return interface which will contain one-to-many entities. But still need to provide custom implementation (Easy to implement). – Mister_Jesus Oct 12 '20 at 16:59

2 Answers2

0

You may have a look at https://github.com/lecousin/lc-spring-data-r2dbc but looks like not yet fully ready to be used. But if your needs are not too complex it may do the job.

For example you can declare links like that:

@Table
public class TableWithForeignKey {
  ...
  @ForeignKey(optional = false)
  private LinkedTable myLink;
  ...
}

@Table
public class LinkedTable {
  ...
  @ForeignTable(joinkey = "myLink")
  private List<TableWithForeignKey> links;
  ...
}

When you want the links to be mapped, you can use either lazy loading or select with join.

If you use the methods findBy... (findById, findAll...) of the Spring repository, only the table of the repository will be loaded. In this case, you can use lazy loading. For that you need to declare a methods, with default body, and your method will be automatically implemented:

  public Flux<TableWithForeignKey> lazyGetLinks() {
    return null; // will be implemented
  }

Another way is to make joins directly in the request. There is currently no support to automatically do joins in a repository (like @EntitiGraph in JPA), but you can implement your methods like this:

public interface MyRepository extends LcR2dbcRepository<LinkedTable, Long> {
  
  default Flux<LinkedTable> findAllAndJoin() {
    SelectQuery.from(LinkedTable.class, "root") // SELECT FROM LinkedTable AS root
      .join("root", "links", "link")            // JOIN root.links AS link
      .execute(getLcClient());                  // execute the select and map entities
  }

}

The result will be all LinkedTable instances, with the list of links loaded together from the database.

Zinc
  • 1,064
  • 3
  • 16
0

Alternatively try Micronaut framework, it adopts the good parts from all existing frameworks and provides a lot of missing features in spring/SpringBoot.

For example, Micronaut Data R2dbc, it provides a collection of annotations(including one to many, many to many, embedded) to define relations like JPA, more simply you can use JPA annotations and JPA like Specifciation to customize query via type safe Criteria APIs.

Create a web application via https://micronaut.io/launch/, add R2dbc and Database drivers to dependencies, you can bring your Spring experience to Micronaut without extra effort.

My Micronaut Data R2dbc example: https://github.com/hantsy/micronaut-sandbox/tree/master/data-r2dbc

Hantsy
  • 8,006
  • 7
  • 64
  • 109