Hibernate version: 3.2.6.ga
Hibernate annotations version: 3.2.1.ga
Hello, i'm doing a migration from xml mappings to hibernate annotation mappings in my application, and then i want to use hibernate search; but i still have a really problem in the transition from xml mappings to hibernate annotations.
At first, i will explain my model, that is a little complex.
I have "users" and "items" tables, and there is a "many-to-many" relation between these entities, and we have a "users_items" relation table. Also, "users_items" represents the item for this especific user, and have the information of creation_date (the date that the item was added to the user), and other stuff.
In the model of objects i have:
User, that contains many UserItem.
UserItem have an UserItemId that have an User and an Item.
UserItem have the creation date and other stuff.
Item have got a set of Users.
Doing this in xml mapping is like that:
User
Code:
<?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.xxx.User" table="users">
<id name="id" column="id" type="java.lang.Long">
<generator class="native"/>
</id>
<set name="userItems" table="users_items" cascade="all">
<key column="user_id"/>
<one-to-many class="com.xxx.UserItem"/>
</set>
</class>
</hibernate-mapping>
UserItem
Code:
<?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.xxx.UserItem" table="users_items" abstract="true">
<composite-id name="id" class="com.xxx.UserItemId">
<key-many-to-one name="item" column="item_id" class="com.xxx.Item"/>
<key-many-to-one name="user" column="user_id" class="com.xxx.User"/>
</composite-id>
<property name="creationDate" column="creation_date" type="java.util.Date" not-null="true" />
</class>
</hibernate-mapping>
Item
Code:
<?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.xxx.Item" table="items" abstract="true">
<id name="id" column="id" type="java.lang.Long">
<generator class="native"/>
</id>
<set name="users" table="users_items" inverse="true">
<key column="item_id"/>
<many-to-many column="user_id" class="com.xxx.User" />
</set>
</class>
</hibernate-mapping>
And this mappins works very good for me, life is good! :D
But when i use Annotations i have a problem with the "users" set inside the item. I dont want that collection updates the database.
Im using the following annotations:
User
Code:
@Entity
@Table(name="users")
public class User {
private Long id;
private Collection<UserItem> userItems;
@Id @GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="user_id")
public Collection<UserItem> getUserItems() {
return userItems;
}
public void setUserItems(Collection<UserItem> userItems) {
this.userItems = userItems;
}
}
UserItem & UserItemId
Code:
@Entity
@Table(name="users_items")
public class UserItem {
private UserItemId id;
private Date creationDate;
@EmbeddedId
public UserItemId getId() {
return id;
}
public void setId(UserItemId id) {
this.id = id;
}
@Column(name="creation_date", nullable=false)
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
}
@Embeddable
public class UserItemId implements Serializable{
private User user;
private Item item;
@ManyToOne
@JoinColumn(name="user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@ManyToOne
@JoinColumn(name="item_id")
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
}
Item, and here is the problemCode:
@Entity
@Table(name="items")
public abstract class Item {
private Long id;
private Set<User> users;
@Id @GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToMany(
targetEntity=User.class
)
@JoinTable(
name="users_items",
joinColumns=@JoinColumn(name="user_id", insertable=false, updatable=false),
inverseJoinColumns=@JoinColumn(name="item_id")
)
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
When i use this code, i have the following problem:
Code:
org.springframework.jdbc.UncategorizedSQLException: Hibernate flushing: Could not execute JDBC batch update; uncategorized SQLException for SQL [insert into users_items (user_id, item_id) values (?, ?)]; SQL state [S1000]; error code [1364]; General error, message from server: "Field 'creation_date' doesn't have a default value"; nested exception is java.sql.BatchUpdateException: General error, message from server: "Field 'creation_date' doesn't have a default value"
Caused by:
java.sql.BatchUpdateException: General error, message from server: "Field 'creation_date' doesn't have a default value"
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1404) ... ... ...
Ok, fine. I undertand. The @ManyToMany in the Item class is trying to insert the new associations, and fails.
In xml mappings with the "inverse=true" this mapping dont try to insert the new associations. But, how can i do this in annotations!?
I cant use something like that:
Code:
@ManyToMany(
mappedBy = "items",
targetEntity = User.class
)
Because there is no "inverse" mapping really. There is other complex mapping that does the "many-to-many" for the Item also.
Any idea for this?
Thanks Anyway.