Hibernate one to one mapping. Schema generation issue - java

I am generating schema with hibernate mapping. But for some reason by one to one mapping is not getting generated properly. Here are my classes:
#Entity
#Table(name = "resturant")
public class Restaurant {
private Integer restid;
private String restaurantName;
private Foursquare foursquare;
#Id
#Column(name = "restid")
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return restid;
}
public void setId(Integer id) {
this.restid = id;
}
#OneToOne(fetch = FetchType.LAZY, mappedBy = "restaurant", cascade = CascadeType.ALL)
public Foursquare getFoursquare() {
return foursquare;
}
public void setFoursquare(Foursquare foursquare) {
this.foursquare = foursquare;
}
#Column(name = "restname")
public String getRestaurantName() {
return restaurantName;
}
public void setRestaurantName(String restaurantName) {
this.restaurantName = restaurantName;
}
}
and,
#Entity
#Table(name = "foursquare")
public class Foursquare {
private Integer foursquareid;
private Restaurant restaurant;
#Id
#Column(name = "fsid")
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer getFoursquareid() {
return foursquareid;
}
public void setFoursquareid(Integer foursquareid) {
this.foursquareid = foursquareid;
}
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
public Restaurant getRestaurant() {
return restaurant;
}
public void setRestaurant(Restaurant restaurant) {
this.restaurant = restaurant;
}
}
My hbm file looks like:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- You need to complete the configuration here. This is just a sample,
you should use a connection pool -->
<property name="connection.url">jdbc:mysql://localhost:3306/menus3</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.jdbc.batch_size">50</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<mapping class="Restaurant" />
<mapping class="Foursquare" />
</session-factory>
</hibernate-configuration>
Here is my HibernateUtil class:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public final class HibernateUtil {
private static SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration().configure()
.buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
private HibernateUtil() {
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
I am running a simple class to generate the schema by just loading the configuration:
public class Test {
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
session.close();
}
}
This should create a foreign key of restid in Foursquare table but it does not. The sql looks like:
Hibernate: drop table if exists foursquare
Hibernate: drop table if exists resturant
Hibernate: create table foursquare (fsid integer not null auto_increment, idinfoursquare varchar(255), primary key (fsid))
Hibernate: create table resturant (restid integer not null auto_increment, restname varchar(255), staddress varchar(255), primary key (restid))
Can anyone point out why the one to one mapping is not getting reflected in my DB? Why the foreign key column is not getting generated?

You used #PrimaryKeyJoinColumn. The #PrimaryKeyJoinColumn annotation does say that the primary key of the entity is used as the foreign key value to the associated entity. So foreign key is not getting generated. To generate foreign key you should remove #PrimaryKeyJoinColumn annotaion.
#OneToOne(fetch = FetchType.LAZY)
//#PrimaryKeyJoinColumn Remove this annotation.
public Restaurant getRestaurant() {
return restaurant;
}

Related

Hibernate acessing table in schema other than dbo results with Schema-validation: missing table

I have a datasource that has two schemas: dbo and example.
I've created a table in dbo schema called A, and mapped it in hibernate:
#Entity
#Table(name = "A")
public class ATable {
private Integer id;
#Id
#Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
It runs without any errors as expected, I then proceeded to move the table to example schema with the following statement (runs successfully):
alter schema example transfer dbo.A
And changed the hibernate class as well:
#Entity
#Table(name = "A", schema = "example")
public class ATable {
private Integer id;
#Id
#Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
But upon running it, it throws the following exception, and exit the program.
INFO: HHH000262: Table not found: A
Exception in thread "main" org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [A]
at org.hibernate.tool.schema.internal.SchemaValidatorImpl.validateTable(SchemaValidatorImpl.java:130)
at org.hibernate.tool.schema.internal.SchemaValidatorImpl.performValidation(SchemaValidatorImpl.java:100)
at org.hibernate.tool.schema.internal.SchemaValidatorImpl.doValidation(SchemaValidatorImpl.java:65)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:184)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:65)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:459)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:711)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:727)
at com.venditio.Application.main(Application.java:21)
I also tried using the following table annotation instead:
#Table(name = "example.A")
But it throws somewhat the same exception:
INFO: HHH000262: Table not found: example.A
Sep 22, 2017 3:53:36 PM org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl processGetTableResults
INFO: HHH000262: Table not found: example.A
Exception in thread "main" org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [example.A]
at org.hibernate.tool.schema.internal.SchemaValidatorImpl.validateTable(SchemaValidatorImpl.java:130)
at org.hibernate.tool.schema.internal.SchemaValidatorImpl.performValidation(SchemaValidatorImpl.java:100)
at org.hibernate.tool.schema.internal.SchemaValidatorImpl.doValidation(SchemaValidatorImpl.java:65)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:184)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:65)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:459)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:711)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:727)
at com.venditio.Application.main(Application.java:21)
It seems that I need to somehow configure hibernate to support the extra schema, but don't understand how.
Application:
public class Application {
private static SessionFactory sessionFactory;
public static void main(String[] args) {
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
sessionFactory.openSession().close();
}
}
And hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--MSSQL-->
<property name="hibernate.connection.url">jdbc:jtds:sqlserver://localhost:1433/d1</property>
<property name="connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
<property name="hibernate.connection.username">a</property>
<property name="hibernate.connection.password">1</property>
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<!--Global-->
<property name="hibernate.connection.pool_size">10</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">validate</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping class="com.a.A" />
</session-factory>
</hibernate-configuration>
Turns out, removing the following line from hibernate.cfg.xml did the trick
<property name="hibernate.hbm2ddl.auto">validate</property>

Hibernate envers is not updating manually added columns in REVINFO with annotation

I am using plain java to hibernate standalone application with Hibernate Envers for getting updates of changes made in table's columns, I am using sql server as my Database, and I am new in envers.
Here is my "CustomRevisionEntity.java"
#Entity
#AuditTable("REVINFO")
#RevisionEntity(CustomRevisionListener.class)
public class CustomRevisionEntity {
#Column (name = "USERNAME", length = 50)
private String username;
#Id
#GeneratedValue
#RevisionNumber
#Column (name = "REV", unique = true, nullable = false)
private int id;
#Temporal(TemporalType.DATE)
#Column (name = "REVTSTMP", nullable = false, length = 15)
#RevisionTimestamp
private Date timestamp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
CustomRevisionListener.java
public class CustomRevisionListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity ;
String userName = Hibernate_Connection.getloggedUser();
revision.setUsername(userName);
}
}
Hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="hibernate.connection.url">jdbc:sqlserver://localhost:1433;instance=SQLEXPRESS_2012;DatabaseName=ETS_V11_DEV;integratedSecurity=true</property> -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> -->
<property name="show_sql">true</property>
<property name="use_sql_comments">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping class= "Domain_hibernate_SQLServer.Domain"/>
<mapping class= "Domain_hibernate_SQLServer.CustomRevisionEntity"/>
</session-factory>
</hibernate-configuration>
Problem: While using hbm.xml file then it is adding value on username column,
but while I am using Annotation for getting value that time is taking null value as it is not recognizing extra column property that I have added, but
While using annotation, its inserting null values in username columns
It is taking values like this with annotation while seeing sql code on console
/* insert org.hibernate.envers.DefaultRevisionEntity
*/ insert
into
REVINFO
(REVTSTMP)
values
(?)
Table has only 3 columns, 1 is REV, i.e, autoincrement, 2nd is REVTSTMP, nd 3rd is USERNAME, and Its not taking username,
What I am missing, If you need more information then please comment
I think the problem comes from your annotation config so can post your hbm.xml file and the class used for the anotation config?

Hibernate won't create table even though it shows in the sql

Hibernate won't create a specific table called "Product", even though it shows the create table command in the sql.
Category table gets created just fine...
These are classes ;
** BaseObject.java **
#MappedSuperclass
public class BaseObject implements Serializable
{
public static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Category.java
#Entity
public class Category extends BaseObject {
private String name;
#OneToMany(fetch=FetchType.LAZY,mappedBy="category",orphanRemoval=true)
private List<Product> products;
#OneToOne(optional=true)
private Category parent;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public Category getParent() {
return parent;
}
public void setParent(Category parent) {
this.parent = parent;
}
}
Product.java
#Entity
public class Product extends BaseObject{
#ManyToOne
private Category category;
private String jargonCode;
private int order;
private String dataTableJson;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getDataTableJson() {
return dataTableJson;
}
public void setDataTableJson(String dataTableJson) {
this.dataTableJson = dataTableJson;
}
public String getJargonCode() {
return jargonCode;
}
public void setJargonCode(String jargonCode) {
this.jargonCode = jargonCode;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
Spring Conf
<jee:jndi-lookup id="dataSource" jndi-name="${jdni.dataSource}"
expected-type="javax.sql.DataSource" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.dataCollector.pojo.Category</value>
<value>com.dataCollector.pojo.Product</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.showSql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.action}</prop>
</props>
</property>
</bean>
The product won't get created. The strange thing is, it puts the create table command in the sql...
Hibernate: alter table Category drop foreign key FK_p6elut499cl32in8b8j8sy2n4
Hibernate: alter table Product drop foreign key FK_b7afq93qsn7aoydaftixggf14
Hibernate: drop table if exists Category
Hibernate: drop table if exists Product
Hibernate: create table Category (id bigint not null auto_increment, name varchar(255), parent_id bigint, primary key (id))
Hibernate: create table Product (id bigint not null auto_increment, dataTableJson varchar(255), jargonCode varchar(255), order integer not null, category_id bigint, primary key (id))
Hibernate: alter table Category add constraint FK_p6elut499cl32in8b8j8sy2n4 foreign key (parent_id) references Category (id)
Hibernate: alter table Product add constraint FK_b7afq93qsn7aoydaftixggf14 foreign key (category_id) references Category (id)
I really don't understand why.. I use MySQL server.
And I've tried setting hibernate.hbm2ddl.auto to both create and create-drop. But nothing. Can anyone help me ?
Try to change the 'order' column name, is a reserved word, formally the sql is correct by I had a similar issue calling a column 'user' instead of 'userId'

Hibernate: How to join two tables with one of it doesn't have an id?

My two tables (in SQL Server):
create table cluster (
id bigint primary key identity(1,1),
name varchar(100)
)
create table cluster_member (
cluster_id bigint,
member_name varchar(100)
)
The table cluster_member doesn't have an id. The column cluster_id is like a foreign key, reference to the id column in cluster table.
I used Hiberate Tools to generate 2 #Entity classes and a #Embeddable class. I added some class variables and #OneToMany and #ManyToOne annotations trying to join the two tables. But I got an error saying:
org.hibernate.MappingException: Foreign key (FK_hk6sas3oycvcljwbjar7p9ky3:cluster_member [cluster_id,member_name])) must have same number of columns as the referenced primary key (cluster [id])
The error message is pretty clear. But I don't know how to fix it. Please help.
Here is my code:
Cluster.java:
#Entity
#Table(name = "cluster" )
public class Cluster implements java.io.Serializable {
private long id;
private String name;
private Set<ClusterMember> members;
#Id
#Column(name = "id", unique = true, nullable = false)
public long getId() {
return this.id;
}
#Column(name = "name", length = 100)
public String getName() {
return this.name;
}
#OneToMany(mappedBy = "id")
public Set<ClusterMember> getMembers() {
return members;
}
}
ClusterMember.java:
#Entity
#Table(name = "cluster_member" )
public class ClusterMember implements java.io.Serializable {
private ClusterMemberId id;
private Cluster cluster;
#EmbeddedId
#AttributeOverrides({ #AttributeOverride(name = "clusterId", column = #Column(name = "cluster_id")),
#AttributeOverride(name = "memberName", column = #Column(name = "member_name", length = 100)) })
public ClusterMemberId getId() {
return this.id;
}
#ManyToOne
#JoinColumn(name = "cluster_id")
public Cluster getCluster() {
return cluster;
}
}
ClusterMemberId.java:
#Embeddable
public class ClusterMemberId implements java.io.Serializable {
private Long clusterId;
private String memberName;
#Column(name = "cluster_id")
public Long getClusterId() {
return this.clusterId;
}
#Column(name = "member_name", length = 100)
public String getMemberName() {
return this.memberName;
}
}
main function:
#SuppressWarnings("deprecation")
public static void main(String[] args) {
sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria("my.hibernate.table.Cluster");
criteria.add(Restrictions.like("name", "%ABC%"));
#SuppressWarnings("unchecked")
List<Cluster> clusters = criteria.list();
for (Cluster cluster: clusters) {
System.out.println(cluster.toString());
}
tx.commit();
sessionFactory.close();
}
hibernate.cfg.xml
<mapping class="my.hibernate.table.Cluster" />
<mapping class="my.hibernate.table.ClusterMember" />
Try changing this:
#OneToMany(mappedBy = "id")
public Set<ClusterMember> getMembers() {
return members;
}
to
#OneToMany(mappedBy = "cluster")
public Set<ClusterMember> getMembers() {
return members;
}
and add insertable/updatable to false on the associated ManyToOne mapping.
#ManyToOne
#JoinColumn(name = "cluster_id", insertable="false", updatable="false")
public Cluster getCluster() {
return cluster;
}
Because you are not really interested in the ClusterMember.id but in the FK linking back to Cluster.
In Hibernate you cannot use the same column in to different mapping. The "ClusterMember" already uses "cluster_id" for the #Id property, hence if you plan on using for a ManyToOne association, you need to instruct Hibernate to ignore any changes to this end (inserts and updates should be ignored).
Also you can use Hibernate's #MapsId annotation, for composite identifiers with alternate associated mappings.

Getting " org.apache.openjpa.persistence.PersistenceException: null keys not allowed" error when persist objects.

I am using OpenJPA with Eclipse to persist object. I created a simple one to one unidirectional application. But it is giving Foreign key null error.
Student Entity
#Entity
public class Student implements Serializable {
#Id
private int id;
private String name;
private static final long serialVersionUID = 1L;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "dept_id", unique = true, nullable = true, insertable = true, updatable = true, referencedColumnName = "id")
private Department department;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public String toString() {
return "\n\nID:" + id + "\nName:" + name + "\n\n" + department;
}
}
Department Entity
#Entity
#Table(name = "department")
public class Department implements Serializable {
#Id
private int id;
private String name;
private static final long serialVersionUID = 1L;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String deptName) {
this.name = deptName;
}
public String toString() {
return "Department id: " + getId() + ", name: " + getName();
}
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="IBMJPADemo" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>com.ibm.jpa.onetoone.model.Department</class>
<class>com.ibm.jpa.onetoone.model.Student</class>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:mysql://localhost:3306/test" />
<property name="openjpa.ConnectionDriverName" value="com.mysql.jdbc.Driver" />
<property name="openjpa.ConnectionUserName" value="root" />
<property name="openjpa.ConnectionPassword" value="root" />
<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO" />
<property name="openjpa.RuntimeUnenhancedClasses" value="supported"/>
<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/>
<!-- property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)" /-->
<!-- property name="openjpa.jdbc.MappingDefaults"
value="ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict" /-->
</properties>
</persistence-unit>
</persistence>
Client Program
public class OneToOneClient {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("IBMJPADemo");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Student student = new Student();
student.setId(2537);
student.setName("K.Senthuran");
Department dept = new Department();
dept.setId(100);
dept.setName("IT");
student.setDepartment(dept);
em.persist(student);
em.flush();
tx.commit();
em.close();
}
}
Error
Exception in thread "main" org.apache.openjpa.persistence.PersistenceException: null keys not allowed
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1817)
at org.apache.openjpa.kernel.DelegatingBroker.flush(DelegatingBroker.java:1037)
at org.apache.openjpa.persistence.EntityManagerImpl.flush(EntityManagerImpl.java:652)
at com.ibm.jpa.onetoone.client.OneToOneClient.main(OneToOneClient.java:32)
Caused by: java.lang.NullPointerException: null keys not allowed
at org.apache.commons.collections.map.AbstractReferenceMap.put(AbstractReferenceMap.java:248)
at org.apache.openjpa.kernel.ManagedCache.assignObjectId(ManagedCache.java:189)
at org.apache.openjpa.kernel.BrokerImpl.assignObjectId(BrokerImpl.java:4949)
at org.apache.openjpa.kernel.BrokerImpl.setStateManager(BrokerImpl.java:4046)
at org.apache.openjpa.kernel.StateManagerImpl.assertObjectIdAssigned(StateManagerImpl.java:636)
at org.apache.openjpa.kernel.StateManagerImpl.afterFlush(StateManagerImpl.java:1084)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2162)
at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2037)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1808)
... 3 more
Please help to solve this issue.
Thanks & Regards,
K.Senthuran
Since you are using Uni-Directional Mapping, so persisting your Student will not persist your Department too. So, you need to make sure that, while persisting the Student, the Department entity reference used is already persisted in the database, else you will get exception.
So, just persist the department, before you persist the student. I think that will solve your issue.
If you want that, persisting your student also persist the department, then you would need to use bi-directional mapping. i.e. Use a reference of Student in Department, with #OneToOne mapping, specifying a mappedBy attribute.
I found the solution for this issue.
First of all we have to mention the primary key attribute with #Id and #Column annotation.
Then we have to add the following line in persistence.xml.
<property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)" />

Categories

Resources