The following hibernate mapping file generates the java class and the DEPARTMENT table as expected but it doesn't create the DPT_TEACHERS table in the DB, why not ?
<hibernate-mapping>
<class name="hibernate.Department" table="DEPARTMENT">
<id name="id" column="ID">
<generator class="native"/>
</id>
<property name="subject" column="SUBJECT" type="string"/>
<set name="teachers" table="DPT_TEACHERS">
<key column="ID"/>
<one-to-many class="hibernate.Teacher"/>
</set>
</class>
</hibernate-mapping>
You need to add property
hibernate.hbm2ddl.auto
with your database connection properties in your hibernate.cfg.xml to create schema automatically.
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/Test?createDatabaseIfNotExist=true</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="connection.pool_size">10</property>
table="DPT_TEACHERS" is not required. There is no need for another table to create a 1:N relationship. key column="ID" is confusing, it should be key column="TEACHER_ID" so it can be added in Teacher table as a 1:N relationship
Related
I'm making this simple app using Hibernate to do some CRUD operations. I'm having this error in the query generated by hibernate
Config XML:
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/library</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.default_schema">library</property>
<property name="hbm2ddl.auto" value="create"/>
<!-- Mappings -->
<mapping resource="librarysystem/mappings/Role.hbm.xml"/>
<mapping resource="librarysystem/mappings/Librarian.hbm.xml"/>
<mapping resource="librarysystem/mappings/Task.hbm.xml"/>
<mapping resource="librarysystem/mappings/Library.hbm.xml"/>
</session-factory>
</hibernate-configuration>
POJO:
public class Library implements java.io.Serializable {
private int id;
private String name;
private Set librarians = new HashSet(0);
//Constructors, getters and setters...
}
Mapping:
<hibernate-mapping>
<class name="librarysystem.entities.Library" table="library" catalog="library" optimistic-lock="version">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<property name="name" type="string">
<column name="name" length="45" />
</property>
<set name="librarians" table="librarian" inverse="true" lazy="true" fetch="select">
<key>
<column name="libraryid" not-null="true" />
</key>
<one-to-many class="librarysystem.entities.Librarian" />
</set>
</class>
</hibernate-mapping>
Code to get the list:
List<Library> libraries = session.createQuery("FROM Library").list();
When I run a query to get the list of libraries, an exception occurs saying that the query syntax is wrong
the log output of the query is:
select
library0_.id as id1_2_,
library0_.name as name2_2_
from
library.library.library library0_
How did the library.library.library happened?
Any help please?
I've given the minimum details as I thought was necessary. If you need more code to find the error (like other POJOs and mappings), please inform me
How did the library.library.library happened? Any help please?
I'm no expert here but I think the tripple library here comes from the table being named library within a Database (catalog) named library.
<class name="librarysystem.entities.Library" table="library" catalog="library" optimistic-lock="version">
The table name and the catalog name are the same. So we are looking for a catalog called library library within which we want a table called library library.library. Although I'm not 100% on the third library, I think I'm in the right direction.
On a side note, I find it easier to work with hibernate annotation instead of xml mapping.
Difference between annotation and xml mapping in Hibernate
XML mapping example
Annotation example
I am using hibernate 4.1.9. I have Users, and the Users have a list of Accounts, and Accounts have list of Transactions. Here is my hbm.xml
<?xml version="1.0"?>
<class name="User" table="users">
<id name="userId" column="userid">
<generator class="increment"/>
</id>
<property name="username" column="username" not-null="true"/>
<property name="password" column="password" not-null="true"/>
<property name="registerDate" type="timestamp" column="register_date"/>
<list name="accounts" table="accounts" inverse="true" cascade="all">
<key column="userid" not-null="true"/>
<index column="accountid"/>
<one-to-many class="com.joe.data.Account"/>
</list>
</class>
<class name="Account" table="accounts">
<id name="accountId" column="accountid">
<generator class="increment"/>
</id>
<property name="balance" type="big_decimal" column="balance"/>
<property name="lastModified" type="timestamp" column="last_modified"/>
<list name="txns" table="transactions" inverse="true" cascade="all">
<key column="accountId" not-null="true"/>
<index column="transactionId"/>
<one-to-many class="com.joe.data.Transaction"/>
</list>
<many-to-one name="userId" class="User" column="userid" not-null="true"
unique="true" cascade="all"/>
<many-to-one name="accountType" class="AccountType" column="account_type"
not-null="true" cascade="all" unique="true" />
</class>
<class name="Transaction" table="transactions">
<id name="transactionId" column="transactionid">
<generator class="increment"/>
</id>
<property name="description" column="description"/>
<property name="amount" type="big_decimal" column="amount"/>
<property name="dateAdded" column="date_added"/>
<property name="reoccuring" type="numeric_boolean" column="reoccuring"/>
<many-to-one name="category" class="Category" column="category"
not-null="true" cascade="all" unique="true" />
</class>
<class name="Category" table="categories">
<id name="categoryId" column="categoryid"/>
<property name="categoryName" column="categoryname" not-null="true"/>
</class>
<class name="AccountType" table="account_types">
<id name="accountType" column="account_type"/>
<property name="accountName" column="name"/>
</class>
If I leave inverse="true" on the list of accounts (in the User) I get the ConstraintViolationException because the userid is not getting put in the insert query. If I take inverse="true" off of the list of accounts, I get org.hibernate.MappingException: Repeated column in mapping for entity: com.joe.data.Account column: accountid (should be mapped with insert="false" update="false")
To clarify lowercase names are database columns names, camel case are class variable names. I know Transaction class isn't working quite right yet, but if I could get the Accounts to insert I could do the same thing to get the Transactions to insert.
Edit: I added the many-to-one on the Account class and now I am getting another exception where hibernate is complaining about missing a getter for userId in com.joe.data.Account
In order to get inverse="true" work, you need to define many-to-one for User in Account and for Account in Transaction class and mappings.
I am trying to do a one-to-one mapping using hibernate to insert some info into the DB but every time I try I get this error.
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:90)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1217)
at org.springframework.orm.hibernate3.SpringSessionSynchronization.beforeCommit(SpringSessionSynchronization.java:145)
... 12 more
Here is my client.hbm.xml file.
<hibernate-mapping>
<class name="register.Client" table="client" lazy="false">
<id name="clientId" type="string" column="CLIENT_ID"
length="255">
<generator class="increment"></generator>
</id>
<property name="address" type="string" column="ADDRESS"
length="255" />
<property name="email" type="string" column="EMAIL"
length="255" />
<property name="username" type="string" column="USERNAME"
unique="true">
</property>
<!-- Associations -->
<!-- bi-directional one-to-one association to Login -->
<one-to-one name="login" class="login.UsrPwd" lazy="false"
outer-join="auto" />
</hibernate-mapping>
Here is my login.hbm.xml file
<hibernate-mapping>
<class name="login.UsrPwd" table="login">
<id name="username" type="string" column="USER_NAME"> </id>
<property name="password" column="PASSWORD" type="string"/>
<property name="type" column="TYPE_ID" type="int"></property>
<one-to-one name="consultantInfo" class="register.ConsultantInfo"
cascade="all" />
<!-- bi-directional one-to-one association to Client -->
<one-to-one name="client" class="register.Client" cascade="all"/>
</class>
</hibernate-mapping>
when I run my function to add the info to the data base this is the SQL I get.
Hibernate: insert into login (PASSWORD, TYPE_ID, USER_NAME) values (?, ?, ?)
Hibernate: update client set ADDRESS=?, EMAIL=?, USERNAME=? where CLIENT_ID=?
I don't think the second one is supposed to be update because the row doesn't exist yet and that is why it is throwing the exception I am getting. I have no idea why it is doing this any help would be appreciated.
If you need any more info just let me know an I can provide it
I'm terribly new to Hibernate. I've googled for two hours but I still can't figure out, how to make JOIN without using HQL, only by criteria. I have tables Clients(cID, name) and Visits(vID, vcID, date). The relation is one to many (one client can visit multiple times). I would also like to do it without setFetchMode. Just Criteria. Do I have to change the mappping xml?
UPDATE:
this is part of my mapping xml:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
</class>
<class name="Visit" table="Visits">
<id name="vID" column="vID"><generator class="native"/></id>
<property name="vcID" length="10" not-null="true"/>
<property name="date" length="25" not-null="true"/>
</class>
Having a class Client with a list-attribute "visits" that's mapping to your Visit-Entity:
Criteria criteria = session.createCriteria(Client.class);
criteria.addCriteria("visits");
This would create an inner join between your client-table and your visits-table.
Update:
Here you'll find some good examples: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html#querycriteria-associations
Mapping Example
I hardly ever use hibernate mapping xml, however it should read similiar to:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
<bag name="visits">
<key column="vcId"/>
<one-to-many class="Visit"/>
</bag>
</class>
Tell Hibernate that there is a property "visits" which represents a one-to-many relationship.
You need to update you mapping:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
<!-- Declare Set<Visit> visits in the Client class-->
<set name="visits" lazy="false" cascade="all">
<key column="vcID"/>
<one-to-many class="your.package.Visit"/>
</set>
</class>
<class name="Visit" table="Visits">
<id name="vID" column="vID"><generator class="native"/></id>
<!-- and add "Client client" property to your Visit class -->
<many-to-one name="client" column="vcID" lazy="false"/>
<property name="date" length="25" not-null="true"/>
</class>
Then:
Criteria criteria = session.createCriteria(Visit.class).addCriteria("client")
.add(Restriction.eq(...));
or
Criteria criteria = session.createCriteria(Client.class).addCriteria("visits")
.add(Restriction.eq(...));
And Hibernate will join them automatically.
I have two database tables, User and PageComment. Using Hibernate, I'm trying to store a Set of PageComment objects in the User comment (comments made to that user), by using one-to-many relationship in the hbm XML files.
The problem is, I seem to be able to retrieve the set from a User object, but as soon as I try to access any of the objects stored within the set, or even access on of the methods included in the set class (i.e. size()), the JVM throws "org.hibernate.exception.GenericJDBCException: could not initialize a collection". I'm at a loss on this one.
HBM For User Table:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="User" table="user">
<id name="username" column="Username" type="string">
<generator class="assigned"></generator>
</id>
<property name="password" column="Password" type="string"></property>
<property name="firstname" column="Firstname" type="string"></property>
<property name="surname" column="Surname" type="string"></property>
<property name="email" column="Email" type="string"></property>
<property name="admin" column="Admin" type="integer"></property>
<set name="commentsMadeTo" inverse="true">
<key column="userMadeTo"/>
<one-to-many class="PageComment"/>
</set>
</class>
</hibernate-mapping>
HBM For PageComment:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="PageComment" table="PageComment">
<composite-id>
<key-property name="userMadeBy" column="UserMadeBy" type="string" />
<key-property name="userMadeTo" column="UserMadeTo" type="string" />
<key-property name="time" column="Time" type="integer" />
<generator class="assigned"></generator>
</composite-id>
<property name="commentText" column="CommentText" type="string"></property>
<many-to-one name="userMadeTo" column="Username" not-null="true" class="User" />
</class>
</hibernate-mapping>
I'm trying to test the mapping with this method:
Session session = sessionFactory.openSession();
User theUser = (User)session.createQuery("FROM User WHERE Username='Samat'").uniqueResult();
System.out.println("Trying to print out all comments made to 'Samat'");
Set<PageComment> theComments = theUser.getCommentsMadeTo();
for(PageComment p: theComments){
System.out.println(p.getAllData());
}
I spot that there are some problems in the relationship mapping
HBM For User Table:
<set name="commentsMadeTo" inverse="true">
<key column="XXXXXXXX"/>
<one-to-many class="PageComment"/>
</set>
HBM For PageComment:
<many-to-one name="userMadeTo" column="XXXXXXX" not-null="true" class="User" />
The value XXXXX represents the column name on the "many" side (i.e PageComment table in your case) that associates to its "One" side. It should have the same value in both mapping hbm.
Try to change the hbm for user table to:
<set name="commentsMadeTo" inverse="true">
<key column="Username"/>
<one-to-many class="PageComment"/>
</set>