Hi,
I am using hibernate annotations beta 8 and hibernate 3.1.1 with HSQLDB 1.8.0. I have a mapping with @MappedSuperclass and @IdClass which I will follow. When hibernate generates the SQL, it adds an extra field which I haven't defined. Here is my code:
package test;
import javax.persistence.*;
@Entity
@Table (name="cache_entry")
@IdClass (CacheEntryPK.class)
public class CacheEntry extends AbstractDBCacheEntry {
/**
* The primary key.
*/
private CacheEntryPK key;
/**
* The size.
*/
private int size;
public CacheEntry() {
this(new CacheEntryPK());
}
public CacheEntry(CacheEntryPK key) {
this.key = key;
}
/**
* @return the pk1
*/
@Id
public String getKey1() {
return key.getKey1();
}
/**
* This will set the pk1
* @param key1 - the pk1
*/
public void setKey1(String key1) {
key.setKey1(key1);
}
/**
* @return the warehouse code/id.
*/
@Id
public String getKey2() {
return key.getKey2();
}
/**
* This will set the pk2
* @param key2 - the pk2
*/
public void setKey2(String key2) {
key.setKey2(key2);
}
@Column
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final CacheEntry that = (CacheEntry ) o;
if (!key.equals(that.key)) return false;
return true;
}
public int hashCode() {
return key.hashCode();
}
}
package test;
import javax.persistence.*;
import java.sql.Timestamp;
/**
* The cache entry contains the entries primary key, the cached cacheValue and the last updated
* date. This will map to a standard database table. The DB cache entry can be extended as
* long as it is properly mapped to a database table using which underlying mapping
* technology in use.
*/
@MappedSuperclass
public abstract class AbstractDBCacheEntry implements IDBCacheEntry {
/**
* The primary key.
*/
private IDBCachePK key;
/**
* The cacheValue.
*/
private DBCacheValue cacheValue;
/**
* The last update date.
*/
private Timestamp lastUpdatedDate;
/**
* All cache entries need a unique identifier and that is considered its primary key.
* @return the primary key for this entry.
*/
public IDBCachePK getKey() {
return key;
}
/**
* This will set the primary key for the entry.
* @param key - the primary key.
*/
public void setKey(IDBCachePK key) {
this.key = key;
}
/**
* This is the last updated date. This can be used for cache invalidation or eviction.
* @return the last updated date of the cache entry.
*/
@Column (name="last_updated_date")
public Timestamp getLastUpdatedDate() {
return lastUpdatedDate;
}
/**
* This will set the last updated date.
* @param lastUpdatedDate - the last updated date.
*/
public void setLastUpdatedDate(Timestamp lastUpdatedDate) {
this.lastUpdatedDate = lastUpdatedDate;
}
/**
* This will return the internal cache value. This is lazy loaded and requires all external
* requirements for lazy loading to work. This should ONLY be accessed by the DB cache.
* @return the cached value.
*/
@OneToOne (cascade = CascadeType.ALL)
@JoinColumn(name="value_fk")
protected DBCacheValue getCacheValue() {
return cacheValue;
}
protected void setCacheValue(DBCacheValue cacheValue) {
this.cacheValue = cacheValue;
}
}
package test;
import javax.persistence.Embeddable;
/**
* The primary key for the cache.
*/
@Embeddable
public class CacheEntryPK implements IDBCachePK {
private String key1;
private String key2;
public CacheEntryPK() {
}
public CacheEntryPK(String key1, String key2) {
this.key1 = key1;
this.key2 = key2;
}
public String getKey1() {
return key1;
}
public void setKey1(String key1) {
this.key1 = key1;
}
public String getKey2() {
return key2;
}
public void setKey2(String key2) {
this.key2 = key2;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final CacheEntryPK that = (CacheEntryPK) o;
if (!key1.equals(that.key1)) return false;
if (!key2.equals(that.key2)) return false;
return true;
}
public int hashCode() {
int result;
result = key1.hashCode();
result = 29 * result + key2.hashCode();
return result;
}
}
package test;
import javax.persistence.*;
import java.io.Serializable;
/**
* The cache value is an entity that stores serializes the cache value and has an internal id
* that is refernece by the cache entry.
*/
@Entity
@Table (name="cache_value")
public final class DBCacheValue {
/**
* The cache value id.
*/
private long id;
/**
* The cache value.
*/
private Serializable value;
public DBCacheValue(Serializable value) {
this.value = value;
}
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Column
public Serializable getValue() {
return value;
}
public void setValue(Serializable value) {
this.value = value;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final DBCacheValue that = (DBCacheValue) o;
if (id != that.id) return false;
return true;
}
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
}
package test;
import java.sql.Timestamp;
/**
* The cache entry contains the entries primary key, the cached cacheValue and the last
* updated date. This will map to a standard database table. The DB cache entry can be
* extended as long as it is properly mapped to a database table using which underlying
* mapping technology in use.
*/
public interface IDBCacheEntry {
/**
* All cache entries need a unique identifier and that is considered its primary key.
* @return the primary key for this entry.
*/
public IDBCachePK getKey();
/**
* This is the last updated date. This can be used for cache invalidation or eviction.
* @return the last updated date of the cache entry.
*/
public Timestamp getLastUpdatedDate();
}
package test;
import java.io.Serializable;
/**
* This designates the DB cache primary key type.
*/
public interface IDBCachePK extends Serializable {
All the code does is call Session.saveOrUpdate on a cacheEntry.
//wrapper based on session manager
public void saveOrUpdate(Object entity) throws HibernateException {
try {
//begin the transaction or join current
beginTransaction();
//save the object
getCurrentSession().saveOrUpdate(entity);
//commit the transaction
commitTransaction();
} catch (HibernateException ex) {
//rollback transaction
rollbackTransaction();
throw ex;
}
}
Here is what i get:
Running test
Created entry
Hibernate: insert into cache_value (value, id) values (?, null)
Hibernate: call identity()
Hibernate: insert into cache_entry (last_updated_date, value_fk, key, size, key1, key2) values (?, ?, ?, ?, ?, ?)
Caused by: org.hibernate.exception.DataException: could not insert: [test.CacheEntry]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:75)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2078)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2427)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:51)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:243)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:227)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:296)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1007)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:354)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at test.database.SessionManager.commit(SessionManager.java:69)
at test.database.HibernateDataAccessor.commitTransaction(HibernateDataAccessor.java:83)
at test.database.HibernateDataAccessor.saveOrUpdate(HibernateDataAccessor.java:171)
... 25 more
Caused by: java.sql.SQLException: Column count does not match in statement [insert into cache_entry (last_updated_date, value_fk, key, size, key1, key2) values (?, ?, ?, ?, ?, ?)]
at org.hsqldb.jdbc.Util.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.<init>(Unknown Source)
at org.hsqldb.jdbc.jdbcConnection.prepareStatement(Unknown Source)
at org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:442)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:93)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:86)
at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:171)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2048)
... 38 more
I don't know where the extra column key is coming from. It is not in my mapping, but it is part of the class structure. Is it an artifact from the @IdClass or possibly @MappedSuperclass?? is it a bug?
Thanks for any help on this.
|