Missing parameter during merge/persist operation to insert new entity


#1

Hi!

Already posted a similar question on Stackoverflow last week, but since then I’ve managed to change my implementation yet with no success so far.

Situation: I’m trying to persist/merge this entity, newClassification, of a type I called “Classification”, which has all the parameters filled in, except for “id” (see code below, please).
This entity has its parameter classicitationType fully and correctly filled. This last one has its parameter systemType fully and correctly filled as well.

Tried both with entityManager.persist( newClassification ) and entityManager.merge( newClassification ) with the same result: the insert instruction that is being generated by Hibernate does not reflect all the parameters. E.g.: I get…

c=o.h.SQL, m=logStatement, l=92, msg: insert into plat.classification_system (year, system, id) values (?, ?, ?)

…when I was expecting something like…

c=o.h.SQL, m=logStatement, l=92, msg: insert into plat.classification_system (year, class_type_guid, system, id) values (?, ?, ?, ?)

My database model is as follows (omitted constraint definitions here, but if needed I’ll paste them):

create table classification_system (
 id number(19, 0) not null,
 year varchar2(255 char) not null,
 class_type_guid(48 char ) not null,
 system varchar2(255 char) not null,
 primary key (id)
)

create table class_type (
  guid (48 char) not null,
  code varchar2(255 char) not null,
  year varchar2(255 char) not null,
  system_type_guid varchar2(48 char) not null,

  primary key (guid, year)
)

create table system_type (
  guid (48 char ) not null,
  translation varchar2(255 char) not null,
  year varchar2(255 char) not null,
  primary key (guid, year)
)

And my Java classes are as follows:

@Entity
@Table("classification_system", indexes = {
        @Index(name="CLASS_IDX1",columnList="ID"),
        @Index(name="CLASS_IDX2",columnList="ID, SYSTEM"),
        @Index(name="CLASS_IDX3",columnList="ID, CLASS_TYPE_GUID, SYSTEM")
})
class Classification extends ClassificationAbstract implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="classSeq")
    @SequenceGenerator(name="classSeq", sequenceName="CLASS_SEQ", allocationSize=1)
    private Long id;

    // couple of constructors...

    private String system;

    public Classification() {
        super();
    }

    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getSystem() {
        return this.system;
    }
    public void setSystem(String system) {
        this.system = system;
    }
}

@MappedSuperclass
public abstract class ClassificationAbstract implements Serializable {
    private static final long serialVersionUID = 1L;

    @Column(nullable = false)
    @NotNull
    private String year;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
        @JoinColumns(value = {
            @JoinColumn(name = "YEAR", referencedColumnName = "YEAR", insertable = false, updatable = false),
            @JoinColumn(name = "CLASS_TYPE_GUID", referencedColumnName = "GUID", insertable = false, updatable = false)
    })
    private ClassificationType classificationType;


    public ClassificationType getClassificationType() {
        return classificationType;
    }
    public void setClassificationType(ClassificationType classificationType) {
        this.classificationType = classificationType;
    }

}


@Entity
@Table(name="CLASS_TYPE", uniqueConstraints = 
        @UniqueConstraint(columnNames = {"YEAR", "GUID", "SYSTEM_TYPE_GUID"})
)
public class ClassificationType implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private ClassificationTypePK id;

    private String code;
    @Column(name = "YEAR", nullable = false)
    private String year;

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumns({
        @JoinColumn(name = "YEAR", referencedColumnName = "YEAR",
                insertable = false, updatable = false, nullable = false),
        @JoinColumn(name = "SYSTEM_TYPE_GUID", referencedColumnName = "GUID",
                insertable = false, updatable = false, nullable = false)
    })
    private SystemType systemType;

    public ClassificationTypePK getId() {
        return id;
    }
    public void setId(ClassificationTypePK id) {
        this.id = id;
    }
    public String getCode() {
        return this.code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getSystemType() {
        return this.systemType;
    }
    public void setSystemType(String systemType) {
        this.systemType = systemType;
    }
}

@Embeddable
public class ClassificationTypePK implements Serializable {
    private static final long serialVersionUID = 1L;

    private String guid;
    private String year;

    //getters + setters + hashCode + equals implementations...
}

@Entity
@Table(name="SYSTEM_TYPE", uniqueConstraints = 
        @UniqueConstraint(columnNames = {"YEAR", "GUID"})
)
public class SystemType implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private SystemTypePk id;

    private String translation;

    public SystemTypePk getId() {
        return id;
    }
    public void setId(SystemTypePk id) {
        this.id = id;
    }
    public String getTranslation() {
        return translation;
    }
    public void setTranslation(String translation) {
        this.translation = translation;
    }

    //hashCode + equals implementations...
}

@Embeddable
public class SystemTypePL implements Serializable {
    private static final long serialVersionUID = 1L;

    private String guid;
    private String year;

    //getters + setters + hashCode + equals implementations...
}

I’m presently working on a Oracle XE database with Java EE7 + Hibernate 5.0.9 (final).

Am I leaving something out? Or am I doing something that it is just not right?


#2

Why were you expecting that since classification_system has no guid column?


#3

Sorry! What I meant was:

c=o.h.SQL, m=logStatement, l=92, msg: insert into plat.classification_system (year, class_type_guid, system, id) values (?, ?, ?, ?)

Already corrected in the original post.


#4

That’s because you marked the CLASS_TYPE_GUID with insertable = false and updatable = false.

Probably you copy/pasted it from the YEAR mapping where it makes sense since you already mapped the YEAR column. Try removing those 2 attributes and it should work.


#5

I’ve tried that before, and when I compile I get

...jpa-generate-hbmddl failed: Mixing insertable and non insertable columns in a property is not allowed: plat.Classification.classificationType.

Other things I also tried:

  • On ClassificationType + CLASS_TYPE table removed all references to SystemType + SYSTEM_TYPE, for fearing the “link” with the year attribute was causing the trouble and to isolate the issue. The issue persisted.
  • On Classification / ClassificationAbstract type + classification_system table removed year. The insert instruction obviously does not include the year column now, and still does not include the class_type_guid column when actually the attribute classificationType is well formed.

#6

@vlad: I decided to remove the annotations "insertable=false, updatable=false on both JoinColumns and it is working fine now. Thank you so much for your helpful pointers.

It is working but I still have to revert the references to SystemType + SYSTEM_TYPE that I set to @Transient on ClassificationType. Will update once I have all this code up and running.


#7

You can move those attributes to the YEAR column instead.


#8

OK, with everything integrated and working fine, let me tell you what I did, just for the purpose of sharing what I’ve learned:

  • Removed year attribute from ClassificationAbstract, as well as the insertable=false and updatable=false annotations:
@MappedSuperclass
public abstract class ClassificationAbstract implements Serializable {
    private static final long serialVersionUID = 1L;


    @ManyToOne(fetch = FetchType.EAGER, optional = false)
        @JoinColumns(value = {
            @JoinColumn(name = "YEAR", referencedColumnName = "YEAR", nullable = false),
            @JoinColumn(name = "CLASS_TYPE_GUID", referencedColumnName = "GUID", nullable = false)
    })
    private ClassificationType classificationType;

    public ClassificationType getClassificationType() {
        return classificationType;
    }
    public void setClassificationType(ClassificationType classificationType) {
        this.classificationType = classificationType;
    }
}

(Thanks for all your pointers along the thread, @vlad! :slightly_smiling_face:)