Foreign key to entity id instead of entity

I have two entity classes A and B, both using a Long value for primary key id:

@Entity
public class A   {
  private @Id @GeneratedValue Long id;
  ...
}

and

@Entity
public class B   {
  private @Id @GeneratedValue Long id;
  private Long a_id;
  ...
}

I need to have a_id in B be a foreign key reference to the id of an existing instance of A. Adding @ManyToOne(targetClass = A.class) to the field lets Hibernate create the foreign key reference in my test database (PostgreSQL), but obviously there’s something missing on my side:

Trying to insert a new instance of B that uses an existing a_id value doesn’t work; Hibernate throws a PropertyAccessException in, as far as I could debug, in GetterFieldImpl#get(Object owner).

Changing the field definition to private @ManyToOne A a_Id or similar isn*t possible because A and B come from generated code that is not under my control and that is used in a webservice interface; I can only add annotations and a few methods, that’s all.

I’m using Hibernate 6.4.1 btw.

You will have to learn the very basics about OR modelling with JPA/Hibernate. Modelling associations can be done by specifying attributes with the respective types e.g.

@Entity
public class B   {
  private @Id @GeneratedValue Long id;
  @ManyToOne
  @JoinColumn(name = "a_id")
  private A a;
  ...
}

Yes I know, but as I wrote above the classes A and B come from generated code that I have to use more or less as-is; I can only add Hibernate annotations, but no fields. The reason for this is that I’m in the role of a REST service provider that sends entities back to the caller :-/

Then subclass B and introduce the field there. I don’t know your constraints, but you don’t have to send entities back. You can also map entities to these generated DTO classes. I think this is a perfect use case for Blaze-Persistence Entity Views.

I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.

A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:

@EntityView(BEntity.class)
public abstract BDto extends BGenerated {
    public BDto(
        @IdMapping("id") Long id,
        @Mapping("a.id") Long aId
    ) {
        setId( id );
        setAId( aId );
    }
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.

BDto b = entityViewManager.find(entityManager, BDto.class, id);

The Spring Data integration allows you to use it almost like Spring Data Projections: Blaze Persistence - Entity View Module

Page<BDto> findAll(Pageable pageable);

The best part is, it will only fetch the state that is actually necessary!

Thanks for your answer. I guess I found another way:

@Entity
public class B   {
  private @Id @GeneratedValue Long id;
  private @Transient Long a_id;
  private @JsonbTransient @ManyToOne @JoinColumn(name = "a_id") A a;
  ...
}

This makes my code a bit more complex b/c of the necessary mapping between the fields, but OTOH nothing changes for the caller.