Category: Entity Mapping

  • Mastering entity relation mapping in Java

    Mastering entity relation mapping in Java

    Parent Perspective in Entity Mapping

    Have you ever asked: “Should the parent own the relation, with cascade all, and the child DTO not even mention the parent?”

    That’s often a good and clean approach, and here’s why.


    When the Parent Owns the Relation

    @Entity
    public class Person {
        @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
        @JoinColumn(name = "passport_id")
        private Passport passport;
    }
    

    Pros:

    • Clear lifecycle control: When you persist or delete the parent, the child follows.
    • Simpler DTOs: Child DTO doesn’t need a back-reference to parent, reducing nesting.
    • Works great when child is tightly coupled to the parent (e.g., Passport can’t exist without Person).

    DTO Example (clean):

    public record PersonDto(Long id, String name, PassportDto passport) {}
    public record PassportDto(String number, LocalDate issueDate) {}
    

    No need for PersonDto inside PassportDto.


    When to Use This (and Cascade ALL)

    • Child only exists with the parent
    • You’re creating/updating data mostly via parent
    • You want to reduce back-reference clutter and circular mapping
    • You don’t care about child-to-parent navigation (e.g., passport.getPerson())

    ⚠️ When the Child Should Keep a Parent Reference

    @Entity
    public class Passport {
        @OneToOne
        @JoinColumn(name = "person_id")
        private Person person;
    }
    

    Use only when:

    • Child needs context of parent (e.g., audit, filtering, backrefs)
    • You often load children independently and need to reach the parent
    • You’re modeling a bidirectional graph for complex navigation

    In DTOs, this can lead to recursive structures or unnecessary nesting:

    public record PassportDto(String number, LocalDate issueDate, PersonDto person) {}
    

    Which can get ugly, especially in JSON responses.


    Recommended Clean Design

    Let the parent own the relationship, use cascade + orphan removal, and avoid child-to-parent references unless strictly necessary.

    This way:

    • Your APIs stay flat and clean.
    • Your mappers don’t loop.
    • You don’t overfetch or serialize unintended stuff.

    Bonus: @JsonIgnore and Mapping

    If you must have a bidirectional entity model, you can still keep DTOs clean:

    @Entity
    public class Passport {
        @JsonIgnore
        @OneToOne(mappedBy = "passport")
        private Person person;
    }
    

    A test poc implementation can be found here.