1

This is not a duplicated issue, the others don't have the same scenario

My problem is similar to this comment: nullable = false not only create database constraint, but his solution disable all check nullability from hibernate, which I don't want, I want it specifically in this @ManyToOne relationship.

I have a Class RegraValidacao.java that can ocasionally have only one of its @ManyToOne fields setted, the others null. Those @ManyToOne relationships are made with a @JoinTable. What I want is: when generating my DDL via spring.jpa.properties.hibernate.hbm2ddl.auto, I want the @JoinColumns present inside the @JoinTable annotation to generate database constraint NOT NULL on my db2 database ONLY.

So, RegraValidacao can have @ManyToOne nullable relationships with the entities ContaLimite.java and Documento.java. It shall be OK to persist a RegraValidacao that only have a ContaLimite.java, like:

RegraValidacao rgr = new RegraValidacao();
rgr.setContaLimite(new ContaLimite());
rgr.setDocumento(null);

hibernate.save(rgr) // SHOULD WORK

But when I set nullable = false on my JoinColumn, it won't let the field Documento to be null.

@Entity
public class RegraValidacao {

    @ManyToOne
    @JoinTable(name = "CDR_CONTA_LIMITE_REGRA", 
    joinColumns = {@JoinColumn(name = "RGR_ID", nullable = false)},
    inverseJoinColumns = {@JoinColumn(name = "CDL_ID", nullable = false)})
    private ContaLimite contaLimite;

    @ManyToOne
    @JoinTable(name = "DOR_DOCUMENTO_REGRA",
    joinColumns = {@JoinColumn(name = "RGR_ID", nullable = false)}, 
    inverseJoinColumns = {@JoinColumn(name = "DOM_ID", nullable = false)})
    private Documento documento;
}

EDIT: For simplification, I've just put those two attributes, but actually I have 8 pairs of Attributtes/JoinTables in this class. And why? Because this relationship is mutually excluded. If I have a common table relationship @ManyToOne without JoinTables, I would have 7 null fields on database and 1 set. With JoinTables I will not have any null fields, and if there's an id set in a JoinTable, certainly there's an entry on the tables related.

In other words, the relationship with ContaLimite.java and Documento.java should be: optional = true, but their columns on the @JoinTable should be nullable = false.

What I expect: Tables generated via hbm2ddl.auto:

CDR_CONTA_LIMITE_REGRA --> RGR_ID NOT NULL, CDL_ID NOT NULL //OK
DOR_DOCUMENTO_REGRA --> RGR_ID NOT NULL, CDL_ID NOT NULL //OK

Persisting through Hibernate:

RegraValidacao rgr = new RegraValidacao();
rgr.setContaLimite(new ContaLimite());
rgr.setDocumento(null);

hibernate.save(rgr) // SHOULD BE OK!

What I get: Tables generated via hbm2ddl.auto:

CDR_CONTA_LIMITE_REGRA --> RGR_ID NOT NULL, CDL_ID NOT NULL //OK
DOR_DOCUMENTO_REGRA --> RGR_ID NOT NULL, CDL_ID NOT NULL //OK

Persisting through Hibernate:

RegraValidacao rgr = new RegraValidacao();
rgr.setContaLimite(new ContaLimite());
rgr.setDocumento(null);

hibernate.save(rgr) --> Error, cannot persist null

ERROR: org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : br.system.regravalidacao.RegraValidacao.documento; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : br.system.regravalidacao.RegraValidacao.documento

This way I would expect that the columns of the JoinTable would have the NOT NULL constraint, but I can still persist a RegraValidacao with a null Documento.

2 Answers2

0

You're using your join table for two attributes. I wouldn't recommend this.

If I understand your question correctly, you want either the Documento to be null or both the Documento or the ContaLimite to be set. So I would simply allow null for the Documento.

Pieter Delobelle
  • 457
  • 3
  • 10
  • Actually I have two join tables for two different attributtes, why is that wrong? And what I want is: its ok to persist a RegraValidacao entity with Documento null and ContaLimite set, or Documento set and ContaLimite null. In both cases the database jointable CDR shall have the constraints RGR_ID not null and CDL_ID not null, and the join table DOR shall have: RGR_ID not null and DOR_ID not null – Daniel Gonçalves Jan 30 '19 at 11:14
0

Well, I've found a solution that fits but it's not exactly what I wanted. Hope it helps someone someday.

I wanted to disable check null from Hibernate Runtime to a specific attribute of a class, this I couldn't achieve. I could just disable it for my entire class RegraValidacao.java

I created a Spring @Configuration class package scoped with a .properties file (inside my /resources directory) with spring.jpa.properties.hibernate.check_nullability=false on it, and @ComponentScan to my class package:

RegraValidacaoConfiguration.java:

@Configuration
@PropertySource("classpath:regravalidacao.properties")
@EntityScan(RegraValidacaoConfiguration.PACKAGE)
@ComponentScan({RegraValidacaoConfiguration.PACKAGE})
class RegraValidacaoConfiguration {
    static final String PACKAGE = "br.system.regravalidacao";
}

RegraValidacao.java:

package br.system.regravalidacao;
public class RegraValidacao {
    //...
}

regravalidacao.properties:

spring.jpa.properties.hibernate.check_nullability=false

This way, my whole project would still have the spring.jpa.properties.hibernate.check_nullability=true (default) and only my package br.system.regravalidacao will be false.

The only injury is my other attributes inside RegraValidacao (some of them are @OneToOne) will be wrongly affected by check_nullability = false, that's why I wanted something Attribute scoped and not Class scoped. Although this injury isn't that bad because I will still receive an error on those attributes, not from Hibernate Runtime, but from my database. It's pretty ok for me.