hibernate-reactive: ManyToOne lazy association is not loaded with Mutiny.fetch method

Hi, as mentioned in the title of the issue, when you try to load with Mutiny.fetch method an ManyToOne association, the linked entity is instantiated with null fields. The issue is not reproducing when trying to fetch OneToMany association.

Here is reported a minimum code to reproduce the problem


@Entity
@Table(schema = "iot_service", name = "telemetry_data")
public class TelemetryData {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "value", nullable = false)
    private Float value;

    @Column(name = "stored_at", nullable = false)
    private Long storedAt;

    @Column(name = "probed_at", nullable = false)
    private Long probedAt;

    @JoinColumn(name = "feature_id", nullable = false)
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Feature.class)
    private Feature feature;

    public TelemetryData() {
    }

    public TelemetryData(Float value, Long storedAt, Long probedAt, Feature feature) {
        this.value = value;
        this.storedAt = storedAt;
        this.probedAt = probedAt;
        this.feature = feature;
    }

    // Getters and Setters...
}

@Entity
@Table(schema = "iot_service", name = "features")
public class Feature {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "feature_id", nullable = false, unique = true)
    private UUID featureId;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "topic_path", nullable = false, unique = true)
    private String topicPath;

    @Enumerated(value = EnumType.STRING)
    @Column(name = "feature_type", nullable = false)
    private FeatureType featureType;

    @Column(name = "is_running")
    private Boolean isRunning;

    @Column(name = "source_type")
    private SourceType sourceType;

    @Column(name = "running_reference_id")
    private String runningReferenceId;

    @OneToMany(fetch = FetchType.LAZY, targetEntity = TelemetryData.class, mappedBy = "feature")
    private List<TelemetryData> telemetryData;

    // Constructors, getters, setters...
}

@ApplicationScoped
public class TelemetryDataRepository {

    @Inject
    Mutiny.SessionFactory rxSessionFactory;
    
    public Uni<TelemetryData> getLatestDataByFeature(Long featureId) {
        var session = this.rxSessionFactory.openSession();
        return session.createQuery(
                        "from TelemetryData t where t.feature.id = :featureId order by t.probedAt desc",
                        TelemetryData.class
                )
                .setParameter("featureId", featureId)
                .setMaxResults(1)
                .getSingleResultOrNull()
                .call(telemetryData ->
                        Mutiny.fetch(telemetryData.getFeature())
                )
                .call(ignored -> session.flush())
                .call(ignored -> session.close());
    }
}

Edit: Add a sample code to retrieve data fetched by the query

  this.telemetryDataRepository.getLatestDataByFeature(1L)
                .map(telemetryData -> {
                    var telemetryCalendar = Calendar.getInstance();
                    telemetryCalendar.setTimeInMillis(telemetryData.getProbedAt());
                    var telemetryUpdateMessage = new TelemetryUpdateMessage(
                            telemetryData.getFeature().getDevice().getId(), // <----- exception due null pointer exception on  feature.getDevice()
                            telemetryData.getFeature().getId(),
                            telemetryCalendar,
                            telemetryData.getValue()
                    );
                    return telemetryUpdateMessage;
                });

The example below is applicable also if i print the data in a logger

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 28 (22 by maintainers)

Commits related to this issue

Most upvoted comments

Fixed now: was easier than I has estimated.

Yeah, no worries. Please, just add a comment when if start to work on this

Alright, so it looks like we’re going to need a reactive version of AbstractEntityPersister.initializeEnhancedEntityUsedAsProxy() in ReactiveAbstractEntityPersister.

Thanks, I’ve reopened the issue and I will check the new test case later