Unable to find mapping property inside Properties tag

In hibernate Core 5.4.28 I’m trying to execute the following code:

CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
Root<Contract> root = countQuery.from(Contract.class);
Path<Object> path2 = root.get("contractId");

On the execution of “root.get(“contractId”);” , I get the following error message:

java.lang.IllegalArgumentException: Unable to locate Attribute  with the the given name [contractId] on this ManagedType [Contract]
	at org.hibernate.metamodel.model.domain.internal.AbstractManagedType.checkNotNull(AbstractManagedType.java:148) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final]
	at org.hibernate.metamodel.model.domain.internal.AbstractManagedType.getAttribute(AbstractManagedType.java:119) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final]
	

Part of my hibernate mapping is as follows:

<class name="Contract"
		table="CONTRACT">
		<id name="PK" type="long">
			<column name="PK" />
			<generator class="native">

			</generator>
		</id>
		<version name="dbVersion" column="version" type="long" />

		<properties name="uniqueContract" unique="true">
			<!-- Ensure we don't have duplicated contracted inside the same Company-->
			<property name="contractId" type="java.lang.String">
				<column name="CONTRACTID" not-null="true" />
			</property>
			<many-to-one name="Participants"
				class="Participants" fetch="select"
				cascade="none" not-null="true">
				<column name="ParticipantsId" index="IDX_Participants" />
			</many-to-one>
		</properties>
		<property name="isSign" type="java.lang.Boolean">
			<column name="isSign" />
		</property>
</class>

I think my mapping is correct because I have used it multiple times for other purposes and it works as expected. If I change the property “contractId” from inside the Properties tag to Outside it, the error no longer shows and the property is found.

So my questions are, why the code “root.get(“contractId”);” can’t find the property with the current mapping, is there a way(without changing the mapping) to retrieve the property to use in the following code:

CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
Root<Contract> root = countQuery.from(Contract.class);
Path<Object> path2 = root.get("contractId");
countQuery.where(criteriaBuilder.equal(path2, 123));

The <properties/> tag is usually used to declare a virtual property, but the JPA metamodel doesn’t know anything about such virtual properties. So unless the fully qualified property access root.get("uniqueContract").get("contractId") works, you will have to move the property out of the <properties/> tag.

1 Like

The uniqueContract properties is also not visible when executing root.get("uniqueContract").

So I suppose that the only option is to move it outside the <properties/> tag.

Another question surges, is there a problem repeating the property leaving it inside and outside the tag <properties/>? (I don’t want the lose the uniqueness configured in the properties)
In terms of mapping does it stay almost the same?

The hbm.xml model is very limited regarding such mappings. I would recommend you to switch to annotations. With annotations you can specify dedicated indexes and mark them as unique, so you don’t need these virtual properties for that. You can map properties multiple times, but you will have to make sure only one property is insertable="true" updatable="true"

1 Like

Thanks, a lot for the quick responses.
I will be trying this solution:

        <property name="contractId" type="java.lang.String"  insert="false" update="false">
			<column name="CONTRACTID" not-null="true" />
		</property>
		<properties name="uniqueContract" unique="true">
			<!-- Ensure we don't have duplicated contracted inside the same Company-->
			<property name="contractId" type="java.lang.String"  insert="true" update="true">
				<column name="CONTRACTID" not-null="true" />
			</property>
			<many-to-one name="Participants"
				class="Participants" fetch="select"
				cascade="none" not-null="true">
				<column name="ParticipantsId" index="IDX_Participants" />
			</many-to-one>
		</properties>

If you see any problems please tell me, your previous insight helped me quite a while.

After testing I will try to report back here, thanks again.

I would swap the configuration i.e. make the property in the virtual property insert="false" update="false" instead, but other than that, this looks ok to me.

1 Like

Why would you swap that?

Because the properties tag is “virtual”, which implies to me that it is not real, hence it feels wrong to me making that insertable/updatable.

1 Like

Final solution and it is working:

<property name="contractId" type="java.lang.String">
    <column name="CONTRACTID" not-null="true" />
</property>
<many-to-one name="Participants" class="Participants" fetch="select" cascade="none" not-null="true">
    <column name="ParticipantsId" index="IDX_Participants" />
</many-to-one>

<properties name="uniqueContract" unique="true">
    <property name="contractId" insert="false" update="false">
        <column name="CONTRACTID" not-null="true" />
    </property>
    <property name="Participants" insert="false" update="false">
        <column name="ParticipantsId" index="IDX_Participants" />
    </property>
</properties>

Ended up changing the participants for visibility purposes also, and the updatable/insertable property makes more sense as you said.

Thanks for all the help Beikov, any last remarks on the final solution please do so.