How use multiple #Embedded in same entity? - java

I have an embeddable entity in a java web app as follow:
#Embeddable
#Getter
#Setter
public class Address {
private String street;
private String alley;
private int postCode;
}
I use a embedded field in another entity as follow:
#Entity
#Getter
#Setter
public class User {
#Embedded
private Address home;
#Embedded
private Address work;
}
When I run application, Occur error :
org.hibernate.MappingException: Repeated column in mapping for entity:
my.package.User column: alley(should be mapped with insert="false"
update="false").
How can I fix it?
note:
I can't use #AttributeOverrides.
I'm using hibernate 5.2.10.
update:
I use configs in applicationContext.xml as follow:
<bean id="mainSessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>my.package</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.spatial.dialect.postgis.PostgisDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.default_schema">public</prop>
<prop key="hibernate.implicit_naming_strategy">org.hibernate.boot.‌?model.naming.Impli‌?ci‌?tNamingStrategyCompo‌nentPathImpl</prop>
</props>
</property>
</bean>
<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="mainSessionFactory"/>
</bean>

You can achieve using #AttributeOverrides
#Embeddable
#Getter
#Setter
public class Address {
private String street;
private String alley;
private int postCode;
}
#Entity
#Getter
#Setter
public class User {
#Embedded
#AttributeOverrides({
#AttributeOverride(name="street",column=#Column(name="home_street")),
#AttributeOverride(name="alley",column=#Column(name="home_alley")),
#AttributeOverride(name="postCode",column=#Column(name="home_postCode"))
})
private Address home;
#Embedded
#AttributeOverrides({
#AttributeOverride(name="street",column = #Column(name="work_street")),
#AttributeOverride(name="alley",column=#Column(name="work_alley")),
#AttributeOverride(name="postCode",column=#Column(name="work_postCode"))
})
private Address work;
}
UPDATE:
If you don't want to use #AttributeOverrides then try overring hibernate naming strategy using ImplicitNamingStrategyComponentPathImpl.INSTANCE

I solve my problem and I want to share the answer:
The key point is defining implicitNamingStrategy:
<bean id="mfNamingStrategy"
class="org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl" />
<bean id="mainSessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="implicitNamingStrategy" ref="mfNamingStrategy" />
<property name="hibernateProperties">
<props>
...
<!-- <prop key="hibernate.implicit_naming_strategy">org.hibernate.boot.‌?model.naming.Impli‌?ci‌?tNamingStrategyCompo‌nentPathImpl</prop> -->
</props>
</property>
</bean>

Related

One to Many mapping using Hibernate and Spring

I am trying to create two join tables ConceptModelDetails and Instructions using a foreign key. Following are my model classes:
ConceptModelDetails:
package com.assignment.model;
#Entity
#Table(name="conceptModelDetails")
public class ConceptModelDetails {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int instructionsId;
private String operationType;
private String conceptModelID;
private String requestor;
private String status;
private Timestamp requestDateTime;
private Timestamp lastExecutedDateTime;
private Timestamp completedDateTime;
#OneToMany(cascade=CascadeType.ALL, mappedBy="conceptModelDetails")
private Set<Instructions> instructions;
public ConceptModelDetails() {}
}
and Instuctions:
package com.assignment.model;
#Entity
#Table(name="instructions")
public class Instructions {
#Id
#GeneratedValue
private int Sno;
private String instruction;
#ManyToOne
#JoinColumn(name="instructionsId")
private ConceptModelDetails conceptModelDetails;
}
Following is applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://192.168.1.79:5432/test" />
<property name="username" value="postgres" />
<property name="password" value="admin" />
</bean>
<bean id="objDAO" class="com.assignment.dao.impl.ConceptModelDAOImpl">
<property name="sessionFactory" ref="sessionfactory" />
</bean>
<bean id="sessionfactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan" value="com.assignment.model"></property>
<property name="annotatedClasses">
<list>
<value>com.assignment.model.ConceptModelDetails</value>
<value>com.assignment.model.Instructions</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionfactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
and Controller:
#RequestMapping(value = "/myCntrl", method = RequestMethod.POST)
public String handler(HttpServletRequest request) {
System.out.println("handler");
// System.out.println(request.getParameter("conceptID"));
// System.out.println(request.getParameter("operationType"));
String[] operations = request.getParameterValues("operations");
Date date = new Date();
Timestamp time = new Timestamp(date.getTime());
ConceptModelDetails conceptModelDetails = new ConceptModelDetails();
conceptModelDetails
.setConceptModelID(request.getParameter("conceptID"));
conceptModelDetails.setOperationType(request
.getParameter("operationType"));
conceptModelDetails.setRequestor(request.getParameter("requestor"));
conceptModelDetails.setRequestDateTime(time);
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
System.out.println("yo");
ConceptModelDAO obj = (ConceptModelDAO)context.getBean("objDAO");
System.out.println("no");
Instructions instructions = new Instructions();
for(int i = 0; i < operations.length; i++){
instructions.setInstruction(operations[i]);
obj.addInstructions(instructions);
}
obj.add(conceptModelDetails);
return "success";
}
Problems when I run this code are:
Same hibernate_sequence is used for both the tables.
Foreign key is not mapped in the Instruction table as seen in the following screenshot.
Please guide what is wrong with the code. I am new to hibernate and spring, so I'd appreciate a detailed explanation. Thanks in advance.
1) You are using the Global sequence generator that hibernate provide by default when no generator is provided as specifed by the JPA Spec.
Change it as follows. Do this to the both of the classes with different sequences for each class.
#Entity
#SequenceGenerator(name="PRIVATE_SEQ", sequenceName="private_sequence")
public class ConceptModelDetails {
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE, generator="PRIVATE_SEQ")
private int instructionsId;
2) Here Instructions class owns the relationship and
therefore you should set ConceptModelDetails object to the Instructions object before saving the Instructions object.
ConceptModelDetails cmd1 = new ConceptModelDetails();
Instructions i = new Instructions()
i.setConceptModelDetails(cmd1);
....
Then save the Instructions object i
Hope this helps.

Hibernate: getter of #OneToMany field in entity returns null in junit test

I have three entities (there're also getters and setters for every field):
public class IndicatorSet {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#NaturalId
#Column(unique=true, nullable=false)
private String code;
#Column(nullable=false)
private String name;
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#JoinTable(
name = "indicator_set_indicators",
joinColumns = #JoinColumn(name = "indicator_set_id"),
inverseJoinColumns = #JoinColumn(name = "indicator_id")
)
private List<Indicator> indicators;
}
public class Indicator {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(nullable=false, unique=true)
private String code;
}
public class IndicatorSetIndicator {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="indicator_id", nullable=false)
private Indicator indicator;
#ManyToOne
#JoinColumn(name="indicator_set_id", nullable=false)
private IndicatorSet indicatorSet;
}
I put in database an IndicatorSet, Indicators and connect it with IndicatorSetIndicator table on my server and in junit test before running the following code.
IndicatorSet set = indicatorSetDAO.get(idOfSet);
List<Indicator> indicators = set.getIndicators();
When I invoke this code on server it works and I see my Indicators in list.
When I try to invoke this code in junit test, I see in list null reference.
And that's strange.
Also when I invoke the following code in junit test, it works perfect and indicators appears in list:
IndicatorSet set = indicatorSetDAO.get(idOfSet);
List<Indicator> indicators = indicatorSetIndicatorDAO.getIndicatorsBySet(set);
DAO uses Criteria API to get list of indicators.
There're this set of annotations on class with tests:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:TestContext.xml")
#Transactional
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class, SessionRequestTestExecutionListener.class })
TestContext.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans [schemes]>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="org.example.monitoring" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<jdbc:embedded-database id="dataSource" type="HSQL" />
<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:db-changelog.xml" />
<property name="contexts" value="test" />
<!-- <property name="dropFirst" value="true" /> -->
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name='packagesToScan' value='pro.sisit.etalon.monitoring.entities' />
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.connection.autocommit">true</prop>
</props>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.web.context.request.RequestScope" />
</entry>
<entry key="session">
<bean class="org.springframework.web.context.request.SessionScope" />
</entry>
</map>
</property>
</bean>
</beans>
Configuration of Hibernate not in test enviroment:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/monitoring" />
</bean>
<bean id='sessionFactory'
class='org.springframework.orm.hibernate4.LocalSessionFactoryBean'>
<property name='dataSource' ref='dataSource' />
<property name='packagesToScan' value='pro.sisit.etalon.monitoring.entities'/>
<property name='hibernateProperties'>
<props>
<prop key='hibernate.dialect'>org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key='hibernate.show_sql'>false</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
How can I make my code work in JUint test?

org.hibernate.hql.ast.QuerySyntaxException: Users is not mapped [from Users users]

Can anybody help me out of this situation?
Users.java
#Entity
#Table(name="users")
public class Users {
#Id
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#Column(name="city")
private String city;
#Column(name="salary")
private Long salary;
#Column(name="email")
private String email;
//getters and setters
}
applicationContext.xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
// Dont Understand whether internaly its reading the class or not!
<property name="packagesToScan" value="com.project.entities"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop> </props>
</property>
</bean>
Method from persistence Layer
public List<Users> getAllUsers(){
String queryString = "from Users users";
List<Users> list = htemp.find(queryString);
return list;
}

Hibernate org.hibernate.MappingException for non-annotated field

This is my POJO, a simple student class.
#Proxy(lazy = false)
#Entity(name = "Students")
public class Student implements Serializable {
private static final long serialVersionUID = -9182600037012718128L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
private String name;
private List<Homework> homework; // <-- the problematic line
public Student(){
}
public getId(){return id;}
public setId(long id){this.id = id;}
public getName(){return name;}
public setName(String name){this.name = name;}
public getHomework(){return homework;}
public setHomework(List<Homework> homework){this.homework = homework;}
}
Unfortunately, even though the homework field is not annotated (since I currently do not want to map it to my DB), I get this exception when running my application:
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: Students, for columns: [org.hibernate.mapping.Column(homework)]
This is my hibernate-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="username" value="root" />
<property name="password" value="root" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="select 1" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.hbm2ddl.auto=update
hibernate.show.sql=true
</value>
</property>
<property name="annotatedClasses">
<list>
<value>com.test.entity.Student</value>
</list>
</property>
</bean>
Any help is appreciated!
Thanks!
You can make non mapped field as transient, to make hibernate not try to map it with DB
private transient List<Homework> homework;
or you can annotate it with #javax.persistence.Transient annotation
#Transient
private List<Homework> homework;
One feature of hibernate is, it tries to map all the fields of Entity class with the corresponding columns of the table. So for the variable homework, it searches for the corresponding column with the same name "homework" (case -insensitive) in the mapped table.
See the documentation here, and it says
Every non static non transient property (field or method depending on
the access type) of an entity is considered persistent, unless you
annotate it as #Transient. Not having an annotation for your property
is equivalent to the appropriate #Basic annotation.

Can we configure Hibernate Without hibernate.cfg.xml

The below is the hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
<property name="hibernate.connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
<property name="hibernate.connection.url">jdbc:derby://localhost:1527/XE</property>
<property name="hibernate.connection.username">username</property>
<property name="hibernate.connection.password">password</property>
</session-factory>
</hibernate-configuration>
I wonder if it's always necessary to use hibernate.cfg.xml in every Hibernate Application or there is any alternative way to configure Hibernate.
You can do this by setting the properties using java
public class TestHibernate {
public static void main(String arg[]) {
Properties prop= new Properties();
prop.setProperty("hibernate.connection.url", "jdbc:mysql://<your-host>:<your-port>/<your-dbname>");
//You can use any database you want, I had it configured for Postgres
prop.setProperty("dialect", "org.hibernate.dialect.PostgresSQL");
prop.setProperty("hibernate.connection.username", "<your-user>");
prop.setProperty("hibernate.connection.password", "<your-password>");
prop.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver");
prop.setProperty("show_sql", true); //If you wish to see the generated sql query
SessionFactory sessionFactory = new Configuration().addProperties(prop).buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Customer user = new Customer(); //Note customer is a POJO maps to the customer table in the database.
user.setName("test");
user.setisActive(true);
session.save(user);
session.getTransaction().commit();
session.close();
}
}
#Entity
#Table(name = "customer", uniqueConstraints = {
#UniqueConstraint(columnNames = "customerid")})
public class Customer implements Serializable{
private String name;
private int customerid;
private boolean isActive;
public Customer() {
}
public Customer(String name, int customerId, boolean isActive) {
this.name = name;
this.customerid = customerId;
this.isActive = isActive;
}
/**
* GETTERS
*/
#Column(name = "name", unique = false, nullable = false, length = 100)
public String getname() {
return name;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "customerid", unique = true, nullable = false)
public int getcustomerid() {
return customerid;
}
#Column(name = "isactive", unique = false, nullable = false)
public boolean getisactive() {
return isActive;
}
/**
* SETTERS
*/
public void setname(String name) {
this.name = name;
}
public void setisactive(boolean isActive) {
this.isActive = isActive;
}
}
It is not necessary, in the session factory bean configuration you can pass these values directly using
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
<prop key="hibernate.show_sql"></prop>
<prop key="hibernate.use_outer_join">true</prop>
</props>
</property>
ex
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
<prop key="hibernate.show_sql"></prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.jdbc.batch_size" >30</prop>
<prop key="hibernate.connection.SetBigStringTryClob">true</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>mypackage</value>
</list>
</property>
</bean>
You can Specify the properties of hibernate.cfg.xml as property injection in spring bean.xml
for example
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
So in similar way you can specify all properties in spring as a dependency for sessionFacory

Categories

Resources