Entity ORM design

Viewed 117

I have four Entities , an Gorilla, a Health Check, Transmitter and a Microchip - I have a question about wiring these entities together.

Gorillas have Health Checks 3-4 times a year so they are OneToMany. Each Gorilla normally has 1 microchip during the course of there life. Microchips are inserted during health checks, but usually only one unless one has fallen out (rare). So I make this OneToMany also on Gorilla to Microchip. Each Gorilla has one Transmitter at a time, but they are replaced every year. So also OneToMany.

I have setup my entities like this:

GORILLA

@Data
public class Gorilla {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;
    @Column(unique = true)
    @NotEmpty(message = "Name must not be null or empty")
    private String name;
   
    @JsonIgnore
    @OneToMany (cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval = true, mappedBy = "gorilla")
    private List<Microschip> listMicroschip = new ArrayList<>();

    @JsonIgnore
    @OneToMany (cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval = true, mappedBy = "gorilla")
    private List<Transmitter> listTransmitter = new ArrayList<>();

    @JsonIgnore
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "gorilla")
    private List<HealthCheck> listHealthCheck = new ArrayList<>();

MICROCHIP

@Data
public class Microchip {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;
    @Column(unique = true)
    @NotEmpty(message = "Name must not be null or empty")
    private String code;
    private LocalDate dateInserted;
    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    private Gorilla gorilla;

HEALTHCHECK

@Data
public class HealthCheck {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Gorilla gorilla;
    // other stuff

When viewing the gorilla entity as a list or a single i normally get the Gorilla with Name, current transmitter, current microchip and sometimes a list of summary fields for the health check.

When viewing a HealthCheck want to retrieve it with Gorilla details, any microchips or transmitters that were attached during that HealthCheck.

The problem with the current design with the Microchips and Transmitters having a relationship with the Gorilla is it makes it easy to get a Gorilla with its current (most recent) transmitter and (most recent) microchip.

This design however makes it hard to get a healthcheck and see which microchip or transmitter was attached on that healthcheck (if any were).

My code for getting the newest microchip for example is:

   default void helperMapping(Gorilla source, GorillaDTO target) {
        if (!source.getListTransmitter().isEmpty()) {
            Transmitter trans = (source.getListTransmitter()
                    .stream()
                    .max(Comparator.comparing(Transmitter::getDateAttached)).get());
            target.setChannel(trans.getChannel());
            target.setChannelOffset(trans.getChannelOffset());
        }

How can I setup the ORM so that:

  1. I don't have to stream over the list of Gorilla's transmitters/microchips each time I want the current one - seems very in-efficent.
  2. I can retrieve a list of healthchecks with any microchips or transmitters relevant to that healthcheck
  3. Less common get a list of all transmitters/microchips for a given Gorilla

(PS: I also tried microchip/transmitter sitting under HealthCheck but they made it even hard to get current microchip/transmitter)

UPDATE

I am considering having a two relationships: Gorilla (One) to Transmitter (Many) HealthCheck (One) to Transmitter (One and Optional)

This way I could easily find the newest Transmitter for any Gorilla (newest in list) and I can see which health check a transmitter was created in.

Thoughts?

1 Answers

I was misunderstanding. If Transmitter and Microchip are only changed during healthcheck, how about this approach?

Gorilla

@Data
public class Gorilla {
    
    @OneToOne // unidirectional
    private Microchip currentMicroChip

    @OneToOne // unidirectional
    private Transmitter currentTransmitter

    @JsonIgnore
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "gorilla")
    private List<HealthCheck> listHealthCheck = new ArrayList<>();

MICROCHIP

@Data
public class Microchip {
   
    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    private HealthCheck healthCheck;

HEALTHCHECK

@Data
public class HealthCheck {

    @JsonIgnore
    @OneToMany (cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval = true, mappedBy = "gorilla")
    private List<Microschip> listMicroschip = new ArrayList<>();

    @JsonIgnore
    @OneToMany (cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval = true, mappedBy = "gorilla")
    private List<Transmitter> listTransmitter = new ArrayList<>();
   
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Gorilla gorilla;
Related