javamicronautmicronaut-data

Loading relations in DB entity does not work


I have this (one-to-many) relationships Fleet -> Configuration -> Software and I'm interested to get all Configurations (with one Fleet and all Software). The problem is that Micronaut do not want to load systems.

Note:

  1. I've tried to use combination of @Join and @JoinSpecifications but it didn't worked
  2. SQL is generated correctly, just the mapping does not work

My classes:

@javax.persistence.Entity
@MappedEntity
@NoArgsConstructor
@Data
@Builder
public class Configuration {

    @Id
    @GeneratedValue(GeneratedValue.Type.AUTO)
    private Long id;

    // other fields

    @NotNull
    @ManyToOne(optional = false)
    @JoinColumn(nullable = false, updatable = false)
    private Fleet fleet;

    @NotNull
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @Relation(value = Relation.Kind.ONE_TO_MANY)
    private List<Software> softwares;
}
@javax.persistence.Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Fleet {

    @Id
    @GeneratedValue(GeneratedValue.Type.AUTO)
    private Long id;

    @NotNull
    @Size(min = 1, max = 255)
    @Column(unique = true)
    private String name;

    // no mapping to Configuration - I'm not interested in it
}
@MappedEntity
@javax.persistence.Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Software implements Entity {

    @Id
    @GeneratedValue(GeneratedValue.Type.AUTO)
    private Long id;

    // other fields

    @NotNull
    @ManyToOne(optional = false)
    @JoinColumn(nullable = false, updatable = false)
    @Relation(value = Relation.Kind.MANY_TO_ONE)
    @ToString.Exclude
    private Configuration configuration;
}
@JdbcRepository(dialect = Dialect.H2)
@JoinSpecifications(
        {
                @Join(value = "softwares", type = Join.Type.LEFT_FETCH),
                @Join(value = "fleet", type = Join.Type.LEFT_FETCH)
        }
)
public interface ConfigurationRepository extends ReactorPageableRepository<Configuration, Long> {}
SELECT configuration_.`id`,
       configuration_.`name`,
       configuration_.`project_name`,
       configuration_.`version_w`,
       configuration_.`version_x`,
       configuration_.`version_y`,
       configuration_.`version_z`,
       configuration_.`version_description`,
       configuration_.`approved_date`,
       configuration_.`imported_date`,
       configuration_.`fleet_id`,
       configuration_softwares_.`id`                  AS softwares_id,
       configuration_softwares_.`name`                AS softwares_name,
       configuration_softwares_.`supplier`            AS softwares_supplier,
       configuration_softwares_.`description`         AS softwares_description,
       configuration_softwares_.`circuit_diagram`     AS softwares_circuit_diagram,
       configuration_softwares_.`comment`             AS softwares_comment,
       configuration_softwares_.`date`                AS softwares_date,
       configuration_softwares_.`version_w`           AS softwares_version_w,
       configuration_softwares_.`version_x`           AS softwares_version_x,
       configuration_softwares_.`version_y`           AS softwares_version_y,
       configuration_softwares_.`version_z`           AS softwares_version_z,
       configuration_softwares_.`version_description` AS softwares_version_description,
       configuration_softwares_.`checksum_cipher`     AS softwares_checksum_cipher,
       configuration_softwares_.`checksum_hash`       AS softwares_checksum_hash,
       configuration_softwares_.`system_id`           AS softwares_system_id,
       configuration_softwares_.`configuration_id`    AS softwares_configuration_id,
       configuration_fleet_.`name`                    AS fleet_name
FROM `configuration` configuration_
         LEFT JOIN `fleet` configuration_fleet_
                   ON configuration_.`fleet_id` = configuration_fleet_.`id`
         INNER JOIN `configuration_software` configuration_softwares_configuration_software_
                    ON configuration_.`id` =
                       configuration_softwares_configuration_software_.`configuration_id`
         INNER JOIN `software` configuration_softwares_
                    ON configuration_softwares_configuration_software_.`software_id` =
                       configuration_softwares_.`id`
ORDER BY configuration_.name ASC, configuration_.approved_date ASC, configuration_.imported_date ASC

Solution

  • To start off with you are mixing JPA and Micronaut Data annotations.

    @javax.persistence.Entity
    @MappedEntity
    
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @Relation(value = Relation.Kind.ONE_TO_MANY)
    

    Which might be possible, haven't tried. But based on your ConfigurationRepository you should be using the Micronaut Data annotations, see the guide on "Access a database with Micronaut Data R2DBC".

    Below is a simple non-reactive version of your code:

    import io.micronaut.data.annotation.GeneratedValue;
    import io.micronaut.data.annotation.Id;
    import io.micronaut.data.annotation.MappedEntity;
    
    @MappedEntity
    public class Fleet {
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String name;
    
        ... getter and setters...
    }
    
    import io.micronaut.core.annotation.Nullable;
    import io.micronaut.data.annotation.GeneratedValue;
    import io.micronaut.data.annotation.Id;
    import io.micronaut.data.annotation.MappedEntity;
    import io.micronaut.data.annotation.Relation;
    
    @MappedEntity
    public class Software {
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String version;
    
        @Relation(Relation.Kind.MANY_TO_ONE)
        private Configuration configurations;
    
        ... getter and setters...
    }
    
    import io.micronaut.core.annotation.Nullable;
    import io.micronaut.data.annotation.GeneratedValue;
    import io.micronaut.data.annotation.Id;
    import io.micronaut.data.annotation.MappedEntity;
    import io.micronaut.data.annotation.Relation;
    
    @MappedEntity
    public class Configuration {
    
        @Id
        @GeneratedValue
        private Long id;
    
        @Relation(value = Relation.Kind.MANY_TO_ONE, cascade = Relation.Cascade.ALL)
        private Fleet fleet;
    
        @Nullable
        @Relation(value = Relation.Kind.ONE_TO_MANY, cascade = Relation.Cascade.ALL)
        private List<Software> softwares;
    
        ... getter and setters...
    }
    
    @JdbcRepository(dialect = Dialect.POSTGRES)
    @JoinSpecifications(
            {
                    @Join(value = "softwares", type = Join.Type.LEFT_FETCH),
                    @Join(value = "fleet", type = Join.Type.LEFT_FETCH)
            }
    )
    //-- or --- 
    //@Join(value = "fleet", type = Join.Type.LEFT_FETCH)
    //@Join(value = "softwares", type = Join.Type.LEFT_FETCH)
    public interface ConfigurationRepository extends CrudRepository<Configuration, Long> {
    }
    

    Micronaut Data documentation