# One-to-many assoc with link table + additional column does not work

**URL:** <https://discourse.hibernate.org/t/one-to-many-assoc-with-link-table-additional-column-does-not-work/7137>\
**Category:** Hibernate ORM\
**Created:** [January 12, 2023, 11:18am UTC](https://discourse.hibernate.org/t/one-to-many-assoc-with-link-table-additional-column-does-not-work/7137 "2023-01-12T11:18:54Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![d00d](https://avatars.discourse-cdn.com/v4/letter/d/49beb7/32.png) [@d00d](https://discourse.hibernate.org/u/d00d)\
**Post date:** [January 12, 2023, 11:18am UTC](https://discourse.hibernate.org/t/one-to-many-assoc-with-link-table-additional-column-does-not-work/7137/1 "2023-01-12T11:18:54Z")

</div>

This is what I have:

**The Profile:**

```auto
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.cl.ilogic.core.rmgt.profile.business.object.RmgtProfileBVOImpl" table="rmgt_t_profile" proxy="com.cl.ilogic.core.rmgt.profile.common.business.object.RmgtProfileBVO">
	    <id name="rowguid" column="rowguid" type="java.lang.Long">
	    		<generator class="sequence">
		        <param name="sequence_name">rmgt_t_profile_rowguid_seq</param>
		    </generator>
	    </id>  
	                         
        <property name="denotation" type="java.lang.String" column="rmgtp_denotation" not-null="true" />         
        <property name="description" type="java.lang.String" column="rmgtp_description" not-null="false" />  
        
        <property name="transportMode" type="java.lang.String" column="rmgtp_transport_mode" not-null="true" />    
        <property name="owner" type="java.lang.String" column="rmgtp_owner" not-null="false" /> 		       
        <property name="minRole" type="java.lang.String" column="rmgtp_min_role" not-null="false" />
        <property name="status" type="java.lang.String" column="rmgtp_status" not-null="true" />
              
        <property name="creationDate" type="timestamp" column="rmgtp_creation_date" /> 
        <property name="creationUser" type="java.lang.String" column="rmgtp_creation_user" />  
        <property name="modificationDate" type="timestamp" column="rmgtp_modification_date" /> 
        <property name="modificationUser" type="java.lang.String" column="rmgtp_modification_user" /> 
        <property name="cloneOfProfileId" type="java.lang.Long" column="rmgtp_t_clone_of_profile_id" />
        <property name="type" type="java.lang.String" column="rmgtp_type" />
        <property name="parentProfileId" type="java.lang.Long" column="rmgtp_parent_profile_id" />
        <property name="showStatus" type="java.lang.Boolean" column="rmgtp_show_status" />
        <property name="showMember" type="java.lang.Boolean" column="rmgtp_show_member" />
        <property name="showNature" type="java.lang.Boolean" column="rmgtp_show_nature" />
        <property name="showAssignment" type="java.lang.Boolean" column="rmgtp_show_assignment" />
        <property name="enabled" type="java.lang.Boolean" column="rmgtp_enabled" />
        
        <property name="shipmentProfileEnabled" type="java.lang.Boolean" 
	       	formula="(SELECT (CASE WHEN count(p.rowguid) = 0 THEN 0 ELSE 1 END) FROM rmgt_t_profile p
    			   			  WHERE EXISTS (SELECT pe.rowguid FROM rmgt_t_profile pe WHERE pe.rmgtp_parent_profile_id = rowguid AND pe.rmgtp_type = 'SHIPMENT DATA' AND pe.rmgtp_status = 'ACTIVE'))" />
    	
    	
        <property name="savingProfileEnabled" type="java.lang.Boolean" 
	       	formula="(SELECT (CASE WHEN count(p.rowguid) = 0 THEN 0 ELSE 1 END) FROM rmgt_t_profile p
    			   			  WHERE EXISTS (SELECT pe.rowguid FROM rmgt_t_profile pe WHERE pe.rmgtp_parent_profile_id = rowguid AND pe.rmgtp_type = 'SAVING PROFILE'))" />
    			   			  
    	<property name="spotRelevant" type="java.lang.Boolean" column="rmgtp_spot_relevant" />
    	
        <set name="groups" table="rmgt_t_group" lazy="false" cascade="all-delete-orphan" order-by="rmgtg_group_order asc">
			<key column="rmgtg_fk_profile_id" not-null="true"/>		
			<one-to-many class="com.cl.ilogic.core.rmgt.profile.business.object.RmgtGroupBVOImpl"/>
        </set>

        <set name="profileValidations" table="rmgt_t_profile_validation" inverse="false" lazy="true" fetch="select" cascade="all-delete-orphan">
            <key property-ref="rowguid">
                <column name="fk_profile_id" not-null="true" />
            </key>
            <many-to-many entity-name="com.cl.ilogic.core.rmgt.profile.business.object.RmgtProfileValidationBVOImpl" >
                <column name="fk_profile_id" not-null="true" />
            </many-to-many>
        </set>

</hibernate-mapping>

```

**The Validation**

```auto
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.cl.ilogic.core.vs.business.object.VsValidationBVOImpl" table="vs_t_validation" proxy="com.cl.ilogic.core.vs.common.business.object.VsValidationBVO">
        <id name="rowguid" column="rowguid" type="java.lang.Long">
	    	<generator class="sequence">
		        <param name="sequence_name">vs_t_validation_rowguid_seq</param>
		    </generator>
	    </id>                      
        <property name="denotation" type="java.lang.String" column="v_denotation" />        		       
        <property name="description" type="java.lang.String" column="v_description" />       
        <property name="path" type="java.lang.String" column="v_path" /> 
        <property name="owner" type="java.lang.String" column="v_owner" />     
        
        <property name="creationDate" type="timestamp" column="v_creation_date" /> 
        <property name="creationUser" type="java.lang.String" column="v_creation_user" />
        <property name="modificationDate" type="timestamp" column="v_modification_date" />
        <property name="modificationUser" type="java.lang.String" column="v_modification_user" />
        <property name="hasMultiColumnValidations" type="java.lang.Boolean" column="v_multicolumn" />
                
        <set name="rules" table="vs_t_v_vr" inverse="false" lazy="false" fetch="select">
			<key column="fk_validation_id"/>		
			<many-to-many class="com.cl.ilogic.core.vs.business.object.VsRuleBVOImpl" column="fk_validation_rule_id" unique="false" order-by="r_description asc"/>
        </set>

        <set name="profileValidations" table="rmgt_t_profile_validation" lazy="false" cascade="all-delete-orphan" >
            <key column="fk_validation_id"/>
            <one-to-many class="com.cl.ilogic.core.rmgt.profile.business.object.RmgtProfileValidationBVOImpl"/>
        </set>
         
    </class>
</hibernate-mapping>

```

**The profileValidation link table:**

```auto
@Entity
@Table(name = "rmgt_t_profile_validation")
@Proxy(proxyClass = RmgtProfileValidationBVO.class)
public class RmgtProfileValidationBVOImpl implements RmgtProfileValidationBVO {
    @EmbeddedId
    private RmgtProfileValidationId id;

    @Column(name = "pv_post_import")
    private Boolean pvPostImport;

    @Override
    @Get(POST_IMPORT)
    public Boolean getPostImport() {
        return pvPostImport;
    }

    @Override
    @Set(POST_IMPORT)
    public void setPostImport(Boolean pvPostImport) {
        this.pvPostImport = pvPostImport;
    }

	@Override
	@Get(PROFILE_ID)
	public Long getProfileId() {
		return id != null ? id.getProfileId() : null;
	}

	@Override
	@Set(PROFILE_ID)
	public void setProfileId(Long profileId) {
		if (id == null) {
			id = new RmgtProfileValidationId();
		}
		id.setProfileId(profileId);
	}

	@Override
	@Get(VALIDATION_ID)
	public Long getValidationId() {
		return id != null ? id.getValidationId() : null;
	}

	@Override
	@Set(VALIDATION_ID)
	public void setValidationId(Long validationId) {
		if (id == null) {
			id = new RmgtProfileValidationId();
		}
		id.setValidationId(validationId);
	}

}

```

The Embedded key:

```auto

@Embeddable
public class RmgtProfileValidationId implements Serializable {
    private static final long serialVersionUID = 6805524598016438604L;

    @OneToMany(mappedBy =)
    @NotNull
    @Column(name = "fk_profile_id", nullable = false, insertable = false, updatable = false)
    private Long profileId;

    @NotNull
    @Column(name = "fk_validation_id", nullable = false, insertable = false, updatable = false)
    private Long validationId;

    public RmgtProfileValidationId(Long profileId, Long validationId) {
        this.profileId = profileId;
        this.validationId = validationId;
    }

}

```

When starting wildfly, I get this error:

```auto

Caused by: org.hibernate.MappingException: collection element mapping has wrong number of columns: com.cl.myApp.core.rmgt.profile.business.object.RmgtProfileBVOImpl.profileValidations type: com.cl.myApp.core.rmgt.profile.business.object.RmgtProfileValidationBVOImpl
        at deployment.tg-clienta.war//org.hibernate.mapping.Collection.validate(Collection.java:320)
        at deployment.tg-clienta.war//org.hibernate.mapping.Set.validate(Set.java:36)
        at deployment.tg-clienta.war//org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:

```

Mappings for Profile and Validations are .hbm.xml because they are legacy tables. I created the profileValidations mapping from scratch. I had it at a point where I could fetch the data but when I removed a validation from a profile and wanted to persist via saveOrUpdate(), Hibernate started to set the fk\_profile\_id to null in the mapping table.

Any idea where one of the two errors come from?

---

<div class="post-metadata">

**Author:** ![d00d](https://avatars.discourse-cdn.com/v4/letter/d/49beb7/32.png) [@d00d](https://discourse.hibernate.org/u/d00d)\
**Post date:** [January 13, 2023, 8:00am UTC](https://discourse.hibernate.org/t/one-to-many-assoc-with-link-table-additional-column-does-not-work/7137/2 "2023-01-13T08:00:33Z")

</div>

Would like to give some more information. In the meantime i switched from EmbeddedId to IdClass to reduce some complexity. When I want to persist a profile with no attached profileValidations, hibernate tries to make an update on the profile table. This is totally wrong, it should remove the line from the mapping table where profile id = the id of my profile that I want to persist.

> error  
> org.springframework.dao.DataIntegrityViolationException: could not execute batch; SQL [update rmgt\_t\_profile\_validation set fk\_profile\_id=null where fk\_profile\_id=?]; constraint [fk\_profile\_id" of relation "rmgt\_t\_profile\_validation]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute batch

My current mapping is this:

**Profile mapping:**

```auto
<hibernate-mapping>
    <class name="com.cl.myapp.core.rmgt.profile.business.object.RmgtProfileBVOImpl" table="rmgt_t_profile" proxy="com.cl.myapp.core.rmgt.profile.common.business.object.RmgtProfileBVO">
	    <id name="rowguid" column="rowguid" type="java.lang.Long">
	    		<generator class="sequence">
		        <param name="sequence_name">rmgt_t_profile_rowguid_seq</param>
		    </generator>
	    </id>  
	   <set name="profileValidations" table="rmgt_t_profile_validation" lazy="false" cascade="all-delete-orphan">
			<key column="fk_profile_id" />
            <one-to-many class="com.cl.myapp.core.rmgt.profile.business.object.RmgtProfileValidationBVOImpl"/>
        </set>
    </class>
</hibernate-mapping>

```

**Profile\_Validations mapping table:**

```auto
@Entity
@IdClass(RmgtProfileValidationId.class)
@Table(name = "rmgt_t_profile_validation")
@Proxy(proxyClass = RmgtProfileValidationBVO.class)
public class RmgtProfileValidationBVOImpl implements RmgtProfileValidationBVO {

	@Id
	@NotNull
	@Column(name="fk_profile_id", insertable = false, updatable = false)
	private Long profileId;

	@Id
	@NotNull
	@Column(name="fk_validation_id", insertable = false, updatable = false)
	private Long validationId;

    @Column(name = "pv_post_import")
    private Boolean pvPostImport;
}

```

**ProfileValidationid class:**

```auto
public class RmgtProfileValidationId implements Serializable {
    private static final long serialVersionUID = 6805524598016438604L;

    private Long profileId;

    private Long validationId;

    public RmgtProfileValidationId(Long profileId, Long validationId) {
        this.profileId = profileId;
        this.validationId = validationId;
    }

    public RmgtProfileValidationId() {
    }
}

```

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [January 13, 2023, 8:15am UTC](https://discourse.hibernate.org/t/one-to-many-assoc-with-link-table-additional-column-does-not-work/7137/3 "2023-01-13T08:15:39Z")

</div>

Hey there, can you please create a JIRA issue for this problem and attach a [reproducer test case](https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java)? Looks like we need to dig into the details of this.

---

<div class="post-metadata">

**Author:** ![d00d](https://avatars.discourse-cdn.com/v4/letter/d/49beb7/32.png) [@d00d](https://discourse.hibernate.org/u/d00d)\
**Post date:** [January 13, 2023, 8:19am UTC](https://discourse.hibernate.org/t/one-to-many-assoc-with-link-table-additional-column-does-not-work/7137/4 "2023-01-13T08:19:40Z")

</div>

Will do so.

But just for the sake of completeness: when I add update=“false” and not-null=“true” to the set in the Profile mapping, hibernate does not fail with an update statement anymore. I will have to dive into the logging to see whats going on there.

```auto
<set name="profileValidations" table="rmgt_t_profile_validation" lazy="false" cascade="all-delete-orphan">
            <key column="fk_profile_id" on-delete="cascade" update="false" not-null="true"/>
            <one-to-many class="com.cl.myapp.core.rmgt.profile.business.object.RmgtProfileValidationBVOImpl" />
</set>

```

---

<div class="post-metadata">

**Author:** ![d00d](https://avatars.discourse-cdn.com/v4/letter/d/49beb7/32.png) [@d00d](https://discourse.hibernate.org/u/d00d)\
**Post date:** [January 16, 2023, 3:27pm UTC](https://discourse.hibernate.org/t/one-to-many-assoc-with-link-table-additional-column-does-not-work/7137/5 "2023-01-16T15:27:28Z")

</div>

When finishing the test case I noticed that the scenario actually works. Hence, the error that caused the odd insert / update statements is obviously caused by our application somehow. Non-issue from hibernate side.
