Best OneToOne mapping recommendation

Hi,

I’m refactoring a project after remove enable_lazy_load_no_trans, and I’m following the best practices from Vlad’s blog.

I read the article: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/ and it suggests that the best way is mapping an unidirectional association.

Actually in my project I have a lot of @OneToOne bidirectional and that’s what I’m doing (I’ll show only three of them):

public class Pessoa extends AppModel implements Serializable {
...
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private PessoaFisica pessoaFisica;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private PessoaJuridica pessoaJuridica;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private Cliente cliente;
...
}

And all of them are like this:

public class PessoaFisica extends AppModel implements Serializable {
...
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Integer id;

    @MapsId
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "id")
    private Pessoa pessoa;
...
}

So when I need to persist my Pessoa entity, I set them like this:

    pessoa.setCliente(new Cliente());
    pessoa.getCliente().setPessoa(pessoa);

    getEntityManager().merge(pessoa);

One of my doubt is if I change to the way which article recommends I have to merge pessoa first and them merge pessoaJuridica, pessoaFisica, cliente and others? Like this:

...
    getEntityManager().merge(pessoa);

    pessoaJuridica.setPessoa(pessoa);
    getEntityManager().merge(pessoaJuridica);

    cliente.setPessoa(cliente);
    getEntityManager().merge(cliente);
...

My second doubt is Pessoa could be PessoaJuridica or PessoaFisica but not both of them (Always one of them are null) and the others @OneToOne like Cliente are optional.

And all over the Controller I already have a lot of verifications that I actually doing, to check if a Pessoa entity is PessoaFisica or PessoaJudirica and if is Cliente or a different type of Pessoa.

What’s the best practice for this situation, I’m asking because if I always JOIN FETCH all of them, I’ll always making a new Query in my Database, is it a good a idea have a flag to define the type of them and do the JOIN FETCH only if it’s necessary?

Thanks in advance

In my project I have a lot of @OneToOne bidirectional

You don’t need those. If you use @MapsId, you don’t need bidirectional associations. Just remove them and save yourself some extra queries.

Thank you for your reply.

I know that, but my mainly two doubts are how to proceed with the situations that I described.

I mean, if a removed the OneToOne bidirectional, should I save all the associations like I ask?

And about the situation of optional entities that I always have to check if they are null or not, is it better use a flag? Because if I still JOIN and checking them, I won’t avoid the extra queries.

When you persist, you need to call persist, not merge.

If you don’t use bidirectional associations, then the parent must be persisted first, then the child.

As for the other question, I don’t really understand what you are asking. Try to ask very clear questions which focus on a single problem at a time.

Ok, I understand now.

About the second question, I asked because it refer to the same changing.

Most of the OneToOne bidirectional that I have, define the behavior of the entity in my Controller. So when I fetched the parent, I use this four child to check a lot of rules.

So there are a lot of in my Controller:

if (pessoa.getCliente() != null)

My question is: what’s a good practice, turn it in a boolean mark in my parent to know when I need to fetch them instead of check if the association is null or any other practice?

Because if I check if the association is null, I’ll keep the extra queries even when the association isn’t satisfied.

That sounds like a hack since you are altering the DB schema with fields that have no meaning in relational model.

Just use JOIN FETCH if you need them initialized, so there will be no extra queries.

Looks like you are trying to do an Joined inheritance model by hand…
PessoaFisica extends Pessoa
PessoaJuridica extends Pessoa
with an @Inheritance(strategy = InheritanceType.JOINED) and maybe even make Pessoa abstract if it can’t be instantiated
could probably do what you are trying to code manually.

Yep, you get it.

My Pessoa (Person) entity can be Cliente (Customer), Fornecedor (Supplier), Transportadora (Shipping Company), Vendedor (Salesman).

But not only one of them, a Pessoa (Person), can be one or more “types”. You p3consulting can be a Customer and Supplier for me.

I know that is wrong like this way:

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private Cliente cliente;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private Fornecedor fornecedor;

    ... //Transportadora and Vendedor is mapped in the same way

So I’m trying to remove this @OneToOne and replace by a boolean mark in Pessoa (Person) and also make all of them @OneToOne unidirectional to avoid extra queries and just fetch what I need to fetch according to the boolean marks.

I didn’t know about the @Inheritance so I’ll study.

Thanks

Like you can use the code like this:
@JoinColumn(name=“Ingredient1”, insertable = true, updatable = true, nullable = true)
@Fetch(FetchMode.JOIN)
private RecipeIngredients ingredient1;

that will not execute the extra query.

if you are using inheritance mapping:

@Inheritance(strategy = InheritanceType.JOINED)
public class Users implements Serializable {

}

correct me if I am wrong

Customer and Supplier are not types of Person but type of Relationships between Person.
Shipping Company, Salesman, … are types of Activities.

You are missing some taxonomies in your model…

I’ll try this way.

Thanks

In my case, Shipping Company and Salesman are specialization of Person.

I need to know if this Person is a Transportadora (Shipping Company), because there will be more fields specific to them and some rules are applied.

Basically all of them are specialization of Person.

… but they should not… but this is out of scope for an Hibernate forum…
it’s more related to semantic, ontology and modelization…

You could try the following here:

@OneToOne(mappedBy="profile", targetEntity=UserAccountImpl.class)
private UserAccount userAccount