I am trying to save entity using hibernate, But somehow not able to see the record in database table, there is no exception is generated.
My Table, Class and hbm.xml file mapping are as follow.
Table : Table has composite primary key as id and mobile columns.
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`mobile` varchar(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`,`mobile`)
);
Classes :
public class StudentPk implements Serializable {
private Integer id;
private String mobile;
public StudentPk() {
super();
}
public StudentPk(Integer id, String mobile) {
super();
this.id = id;
this.mobile = mobile;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((mobile == null) ? 0 : mobile.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StudentPk other = (StudentPk) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (mobile == null) {
if (other.mobile != null)
return false;
} else if (!mobile.equals(other.mobile))
return false;
return true;
}
}
class Student{
private StudentPk pk;
private String name;
--getter-setter-
}
Hibernate Mapping :
<class name="com.Student" table="student" proxy="com.Student">
<composite-id name="id" class="com.StudentPk" >
<key-property name="id" type="java.lang.Integer" column ="id"/>
<key-property name="mobile" type="string" column ="mobile" />
</composite-id>
<property name="name" column="name" type="string" />
</class>
I have also map this hbm.xml file in hibernate.cfg.xml file too.
Please help me for this.
The are few rules you have to keep in mind when writing Primary key class:
The primary key class must be public and must have a public no-arg constructor.
The primary key class must be serializable.
The primary key class must define equals and hashCode methods.
Related
Hibernate 5.6 with Spring 5.3 here.
When creating predicates to fetch data from a table with this code:
CriteriaBuilder cb = this.getSession().getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(aliasToBeanClass);
Root root = cq.from(aliasToBeanClass); // aliasToBeanClass is set to UmsUserRoleVOImpl
predicates.add(cb.equal(root.get(key), value)); // key is set to "userName" - this line is causing the exception
I get this error:
java.lang.IllegalArgumentException: Unable to locate Attribute with
the the given name [userName] on this ManagedType
[com.myapp.ums.business.impl.UmsUserRoleVOImpl]
But the attribute userName is included in my VO, as well as a public setter and it's mapped in my .hbm.xml file:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.myapp.ums.business.impl.UmsUserRoleVOImpl" table="ums_t_user_role"
proxy="com.myapp.ums.common.business.UmsUserRoleVO">
<composite-id>
<key-property name="userName" type="java.lang.String" column="fk_user_id"/>
<key-property name="roleName" type="java.lang.String" column="fk_role_id"/>
</composite-id>
</class>
</hibernate-mapping>
This is my VO:
public class UmsUserRoleVOImpl extends AbstractBasePropertiesImpl implements UmsUserRoleVO {
private static final long serialVersionUID = 2393634151578825216L;
private String roleName;
private String userName;
private List<PmPropertyVO> properties;
public UmsUserRoleVOImpl() {
}
#Get(AbstractBaseProperties.ROWGUID)
#Override
public Long getRowguid() {
return super.getRowguid();
}
#Set(AbstractBaseProperties.ROWGUID)
#Override
public void setRowguid(final Long rowguid) {
super.setRowguid(rowguid);
}
#Get(UmsUserRoleVO.ROLE_NAME)
public String getRoleName() {
return roleName;
}
#Set(UmsUserRoleVO.ROLE_NAME)
public void setRoleName(String roleName) {
this.roleName = roleName;
}
#GetCollection(value = UmsUserRoleVO.PROPERTIES, defaultObject = "com.myapp.pm.business.impl.PmPropertyVOImpl")
public List<PmPropertyVO> getProperties() {
return properties;
}
#SetCollection(value = UmsUserRoleVO.PROPERTIES, defaultObject = "com.myapp.pm.business.impl.PmPropertyVOImpl")
public void setProperties(List<PmPropertyVO> properties) {
this.properties = properties;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof UmsUserRoleVOImpl)) {
return false;
}
UmsUserRoleVOImpl user = (UmsUserRoleVOImpl) o;
if (!(roleName.equals(user.getRoleName()))) {
return false;
}
return userName.equals(user.getUserName());
}
public int hashCode() {
int result = 17;
result = 29 * result + (roleName != null ? roleName.hashCode() : 0);
result = 29 * result + (userName != null ? userName.hashCode() : 0);
return result;
}
public String toString() {
return roleName + " " + userName;
}
#Get(UmsUserRoleVO.USER_NAME)
public String getUserName() {
return this.userName;
}
#Set(UmsUserRoleVO.USER_NAME)
public void setUserName(String userName) {
this.userName = userName;
}
There seems to be something wrong with the mapping, because Hibernate does not find any attribute of the UmsUserRoleVOImpl:
Any idea what could be causing this error?
This question has been asked here before but none of the solutions are working for me.
I am getting following error due to composite key in my SQL Server 2008 table.
java.lang.ExceptionInInitializerError
at HB.Main.<clinit>(Main.java:30)
Caused by: java.lang.IllegalArgumentException: expecting IdClass mapping
at org.hibernate.metamodel.internal.AttributeFactory$3.resolveMember(AttributeFactory.java:977)
at org.hibernate.metamodel.internal.AttributeFactory$5.resolveMember(AttributeFactory.java:1035)
at org.hibernate.metamodel.internal.AttributeFactory.determineAttributeMetadata(AttributeFactory.java:450)
at org.hibernate.metamodel.internal.AttributeFactory.buildIdAttribute(AttributeFactory.java:139)
at org.hibernate.metamodel.internal.MetadataContext.buildIdClassAttributes(MetadataContext.java:388)
at org.hibernate.metamodel.internal.MetadataContext.applyIdMetadata(MetadataContext.java:318)
at org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:221)
at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:274)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:305)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:708)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:724)
at HB.Main.<clinit>(Main.java:26)
Exception in thread "main"
my table looks like this
The classes and mapping is as follows:
Entity Class
package HB;
import java.util.Objects;
public class EmMonthlyPollTablesEntity
{
private int monthlyPollId;
private int tableId;
public int getMonthlyPollId()
{
return monthlyPollId;
}
public void setMonthlyPollId(int monthlyPollId)
{
this.monthlyPollId = monthlyPollId;
}
public int getTableId()
{
return tableId;
}
public void setTableId(int tableId)
{
this.tableId = tableId;
}
#Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
EmMonthlyPollTablesEntity that = (EmMonthlyPollTablesEntity) o;
return monthlyPollId == that.monthlyPollId && tableId == that.tableId;
}
#Override
public int hashCode()
{
return Objects.hash(monthlyPollId, tableId);
}
}
ID Class
package HB;
import java.io.Serializable;
import java.util.Objects;
public class EmMonthlyPollTablesEntityPK implements Serializable
{
private int monthlyPollId;
private int tableId;
public EmMonthlyPollTablesEntityPK()
{
}
public EmMonthlyPollTablesEntityPK(int monthlyPollId, int tableId)
{
this.monthlyPollId = monthlyPollId;
this.tableId = tableId;
}
public int getMonthlyPollId()
{
return monthlyPollId;
}
public void setMonthlyPollId(int monthlyPollId)
{
this.monthlyPollId = monthlyPollId;
}
public int getTableId()
{
return tableId;
}
public void setTableId(int tableId)
{
this.tableId = tableId;
}
#Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
EmMonthlyPollTablesEntityPK that = (EmMonthlyPollTablesEntityPK) o;
return monthlyPollId == that.monthlyPollId && tableId == that.tableId;
}
#Override
public int hashCode()
{
return Objects.hash(monthlyPollId, tableId);
}
}
Main Class
package HB;
import org.hibernate.HibernateException;
import org.hibernate.Metamodel;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import javax.persistence.metamodel.EntityType;
public class Main
{
private static final SessionFactory ourSessionFactory;
static
{
try
{
Configuration configuration = new Configuration();
configuration.setProperty("hibernate.connection.username", "sa");
configuration.setProperty("hibernate.connection.password", "");
configuration.configure();
ourSessionFactory = configuration.buildSessionFactory();
}
catch (Throwable ex)
{
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException
{
return ourSessionFactory.openSession();
}
public static void main(final String[] args) throws Exception
{
final Session session = getSession();
try
{
System.out.println("querying all the managed entities...");
final Metamodel metamodel = session.getSessionFactory().getMetamodel();
for (EntityType<?> entityType : metamodel.getEntities())
{
try
{
final String entityName = entityType.getName();
final Query query = session.createQuery("from " + entityName);
System.out.println("executing: " + query.getQueryString());
for (Object o : query.list())
{
try
{
System.out.println(" " + o);
}
catch (Exception ex)
{
ex.printStackTrace();
;
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
;
}
}
}
finally
{
session.close();
}
}
}
Mapping
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="HB.EmMonthlyPollTablesEntity" table="EM_MONTHLY_POLL_TABLES" schema="dbo" catalog="HB2">
<composite-id mapped="true" class="HB.EmMonthlyPollTablesEntityPK">
<key-property name="monthlyPollId">
<column name="MONTHLY_POLL_ID" sql-type="int"/>
</key-property>
<key-property name="tableId">
<column name="TABLE_ID" sql-type="int"/>
</key-property>
</composite-id>
</class>
</hibernate-mapping>
Entire Intellij Idea Project and table script can be downloaded from here
There is a bug in Hibernate composite id's defined via hbm.xml cause java.lang.IllegalArgumentException in JPA deployment
Root cause
In JPA the composite id must be embeddable. Because the EmMonthlyPollTablesEntityPK class is not embeddable and that is not a component the JPA environment will never support that.
Solution 1: Workaround
Disable metamodel population in hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.ejb.metamodel.population">disabled</property>
<mapping class="..."/>
<!-- ... -->
</session-factory>
</hibernate-configuration>
Solution 2: Drop HBM Mappings and use annotations
As I know HBM mappings are deprecated and will be removed in a future version of Hibernate.
In this case you can choose between using Composite Id, IdClass and EmbeddedId approaches. The following example uses EmbeddedId
Entity class
#Entity
#Table(name = "EM_MONTHLY_POLL_TABLES")
public class EmMonthlyPollTablesEntity implements Serializable {
#EmbeddedId
private EmMonthlyPollTablesEntityPK id;
#Column(name = "NAME")
private String name;
public EmMonthlyPollTablesEntityPK getId() {
return id;
}
public void setId(EmMonthlyPollTablesEntityPK id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EmMonthlyPollTablesEntity)) return false;
EmMonthlyPollTablesEntity that = (EmMonthlyPollTablesEntity) o;
return id.equals(that.id) &&
Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(id, name);
}
}
PK class
#Embeddable
public class EmMonthlyPollTablesEntityPK implements Serializable {
#Column(name = "MONTHLY_POLL_ID", nullable = false)
private int monthlyPollId;
#Column(name = "TABLE_ID", nullable = false)
private int tableId;
public EmMonthlyPollTablesEntityPK() {
}
public EmMonthlyPollTablesEntityPK(int monthlyPollId, int tableId) {
this.monthlyPollId = monthlyPollId;
this.tableId = tableId;
}
public int getMonthlyPollId() {
return monthlyPollId;
}
public void setMonthlyPollId(int monthlyPollId) {
this.monthlyPollId = monthlyPollId;
}
public int getTableId() {
return tableId;
}
public void setTableId(int tableId) {
this.tableId = tableId;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
EmMonthlyPollTablesEntityPK that = (EmMonthlyPollTablesEntityPK) o;
return monthlyPollId == that.monthlyPollId && tableId == that.tableId;
}
#Override
public int hashCode() {
return Objects.hash(monthlyPollId, tableId);
}
}
Delegating PK's getters and setters are available of course.
In this case you don't have to disable metamodel population and you can drop HBM mapping resource from hibernate.cfg.xml
Although I know migrating a huge legacy codebase to JPA annotations and XML mappings is very exhausting I'm sure that is the way to go.
I'm trying to insert mapped object to postgresql database with correct id. This is how i insert:
Session session = Main.getSession();
Transaction rx = session.beginTransaction();
ProductsEntity productsEntity = new ProductsEntity();
productsEntity.setName(nameTextField.getText());
productsEntity.setDescription(descriptionTextArea.getText());
productsEntity.setCategory((ProductCategoriesEntity) categoryComboBox.getSelectedItem());
productsEntity.setPrice(new BigDecimal(1.0));
session.save(productsEntity);
tx.commit();
session.close();
Class with defined sequence:
#Entity
#Table(name = "products", schema = "public", catalog = "shop")
public class ProductsEntity {
private int id;
private String name;
private String description;
private BigDecimal price;
#Id
#Column(name = "id", nullable = false)
#SequenceGenerator(name="pk_sequence",sequenceName="products_id_seq")
#GeneratedValue(strategy=GenerationType.AUTO,generator="pk_sequence")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = false, length = -1)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "description", nullable = false, length = -1)
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Basic
#Column(name = "price", nullable = false, precision = 2)
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductsEntity that = (ProductsEntity) o;
if (id != that.id) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
if (description != null ? !description.equals(that.description) : that.description != null) return false;
if (price != null ? !price.equals(that.price) : that.price != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (price != null ? price.hashCode() : 0);
return result;
}
private ProductCategoriesEntity category;
#ManyToOne
public ProductCategoriesEntity getCategory() {
return category;
}
public void setCategory(ProductCategoriesEntity category) {
this.category = category;
}
}
Last value of postgresql sequence products_id_seq is 4. Hibernate is inserting object with id=0, so first insert was successful, now I'm getting unique constraint violation.
EDIT
I've made sequence work by adding generator
<generator class="identity"/>
in xml mapping definition
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entities.ProductsEntity" table="products" schema="public" catalog="shop">
<id name="id">
<column name="id" sql-type="integer"/>
<generator class="identity"/>
</id>
<property name="name">
<column name="name" sql-type="varchar"/>
</property>
<property name="description">
<column name="description" sql-type="varchar"/>
</property>
<property name="price">
<column name="price" sql-type="numeric(9,2)" precision="9" scale="2"/>
</property>
<many-to-one name="category" column="category_id" class="entities.ProductCategoriesEntity" lazy="false"/>
</class>
</hibernate-mapping>
This works without defining sequence in class. I've also tried to use
#GeneratedValue(strategy=GenerationType.IDENTITY)
in class file but it doesn't work.
If someone has an idea please tell me why only "xml" method works.
Is the sequence "products_id_seq" a DB Sequence?
If Yes, then change your GenerationType from Auto to SEQUENCE.
I've a similar setup with Postgres and setting GenerationType as SEQUENCE and giving allocationSize = 1 worked for me.
Also, ensure your sequence is upto date with the table. If not, Alter the sequence for now so your further updates will not fail.
I am trying to find the correct way to convert the below (Hibernate) XML to JPA annotations:
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<class name="TesTEntry" table="RAW_SCORE">
<composite-id mapped="false" unsaved-value="undefined">
<key-property column="SSN" name="ssn" type="string"/>
<key-property column="SUB_TEST_CD" name="subTestCd" type="string"/>
</composite-id>
<property column="TEST_QY" generated="never" lazy="false"
name="testQy" type="java.lang.Short"/>
<property column="SYS_REC" generated="never" lazy="false"
name="sysRec" type="java.util.Date"/>
<property column="SYS_ID" generated="never" lazy="false"
name="sysId" type="java.lang.String"/>
</class>
Since I have two <key-property> I am not sure if I use #Id, or #EmbeddedId
Since I have two I am not sure if I use #Id, or #EmbeddedId
You mean probably IdClass. And it doesn't matter which one you use.
Let us say, you want to use #IdClass:
Define a class for your ID.
Implement equals and hashCode methods
Implement public default constructor
Implement the Serializable interface
Here is an example implementation (equals & hashCode are generated from IDE):
public class TestEntityPK implements Serializable {
private static final long serialVersionUID = -3424067518791080014L;
private String ssn;
private String subTestCd;
public TestEntityPK() { // }
public TestEntityPK(String ssn, String subTestCd) {
this.ssn = ssn;
this.subTestCd;
}
public String getSsn() {
return ssn;
}
public String getSubTestCd() {
return subTestCd;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((ssn == null) ? 0 : ssn.hashCode());
result = prime * result
+ ((subTestCd == null) ? 0 : subTestCd.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TestEntityPK other = (TestEntityPK) obj;
if (ssn == null) {
if (other.ssn != null)
return false;
} else if (!ssn.equals(other.ssn))
return false;
if (subTestCd == null) {
if (other.subTestCd != null)
return false;
} else if (!subTestCd.equals(other.subTestCd))
return false;
return true;
}
}
And use it in the entity as follows:
#Entity
#Table(name="RAW_SCORE")
#IdClass(TestEntityPK.class)
public class TestEntity {
#Id private String ssn;
#Id
#Column(name="SUB_TEST_CD")
private String subTestCd;
#Column(name="TEST_QY")
private short testQy;
#Column(name="SYS_REC")
#Temporal(TemporalType.DATE)
private Date sysRec;
#Column(name="SYS_ID")
private String sysId;
// getters and setters
}
In a spring mvc app using hibernate and jpa, I recently switched to a composite primary key using an #Embeddable class. As a result, I need to update the JPA query that returns a given object based on its unique id. The following is the JPA code that used to work, but which no longer returns a result:
#SuppressWarnings("unchecked")
public Concept findConceptById(BigInteger id) {
Query query = this.em.createQuery("SELECT conc FROM Concept conc WHERE conc.id =:cid");
query.setParameter("cid", id);
return (Concept) query.getSingleResult();
}
How do I change the above query so that it returns the Concept with the most recent effectiveTime for the given id? Note that id and effectiveTime are the two properties of the ConceptPK composite primary key, and that thus the property definitions and getters and setters for id and effectiveTime are in the ConceptPK class and NOT in the Concept class.
The error thrown by the above is:
Caused by: java.lang.IllegalArgumentException:
Parameter value [786787679] did not match expected type [myapp.ConceptPK]
This is how the primary key is now defined in the Concept class:
private ConceptPK conceptPK;
And here is the code for the ConceptPK class:
#Embeddable
class ConceptPK implements Serializable {
#Column(name="id", nullable=false)
protected BigInteger id;
#Column(name="effectiveTime", nullable=false)
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime effectiveTime;
public ConceptPK() {}
public ConceptPK(BigInteger bint, DateTime dt) {
this.id = bint;
this.effectiveTime = dt;
}
/** getters and setters **/
public DateTime getEffectiveTime(){return effectiveTime;}
public void setEffectiveTime(DateTime ad){effectiveTime=ad;}
public void setId(BigInteger id) {this.id = id;}
public BigInteger getId() {return id;}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final ConceptPK other = (ConceptPK) obj;
if (effectiveTime == null) {
if (other.effectiveTime != null) return false;
} else if (!effectiveTime.equals(other.effectiveTime)) return false;
if (id == null) {
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + ((effectiveTime == null) ? 0 : effectiveTime.hashCode());
hash = 53 * hash + ((id == null) ? 0 : id.hashCode());
return hash;
}
}
To use parts of composite primary key in JPA query, you have to address them using its variable names:
public Concept findConceptById(BigInteger id) {
Query query = this.em.createQuery("SELECT conc FROM Concept conc WHERE conc.conceptPK.id =:cid order by conc.conceptPK.effectiveTime desc");
query.setParameter("cid", id);
return (Concept) query.getSingleResult();
}
I used Concept as entity name assuming the class with #Entity annotation is also named Concept.
This question contains information about similar problem, you may find it useful.
Please try this
#SuppressWarnings("unchecked")
public Concept findConceptById(BigInteger id) {
Query query = this.em.createQuery("from Concept conc WHERE conc.conceptPK.id = :cid order by conc.conceptPK.effectiveTime desc");
query.setParameter("cid", id);
return (Concept) query.getSingleResult();
}
Make sure conceptPK has getter and setter methods in Concept class.