Hi,
I'm getting this exception when I make a call to hibernateTemplate.save(transaction) in my Spring application:
Code:
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: com.nsn.idtv.ibilling.domain.Transaction.event; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: com.nsn.idtv.ibilling.domain.Transaction.event
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:628)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:378)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:639)
at com.nsn.idtv.ibilling.repository.transaction.HibernateTransactionDao.saveTransaction(HibernateTransactionDao.java:81)
at com.nsn.idtv.ibilling.repository.transaction.HibernateTransactionDaoTest.main(HibernateTransactionDaoTest.java:77)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.nsn.idtv.ibilling.domain.Transaction.event
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:167)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:114)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:530)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:518)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:514)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:642)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:373)
... 3 more
Basically, there's three kinds of entities in my ERM: Transactions, Events and Providers. A transaction has a many-to-one relationship to an event, and an event has a many-to-one relationship to a provider. An event is uniquely identified by an eventId and a providerId, so I made them a composite PK.
These are my mapping files:
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.nsn.idtv.ibilling.domain.Transaction" table="TRANSACTIONS">
<id name="transactionId" column="TRANSACTIONID" />
<!-- <property name="providerId" column="PROVIDERID" not-null="true"/>
<property name="eventId" column="EVENTID" not-null="true" /> -->
<!-- <many-to-one name="providerId" class="com.nsn.idtv.ibilling.trax.dto.ProviderDto" not-null="true" >
</many-to-one> -->
<many-to-one name="event" class="com.nsn.idtv.ibilling.trax.dto.EventDto" >
<column name="PROVIDERID" not-null="true" />
<column name="EVENTID" not-null="true" />
</many-to-one>
<property name="mac" column="MAC" not-null="true"/>
<property name="price" column="PRICE" not-null="true"/>
<property name="timestamp" type="timestamp" column="TIMESTAMP" not-null="true"/>
<property name="selectionId" column="SELECTIONID" />
<property name="textString" column="TEXTSTRING" />
<property name="urlpath" column="URLPATH" not-null="true"/>
<property name="exportedForPostProcessing" column="EXPORTEDFORPOSTPROCESSING" not-null="true"/>
<property name="exportedForBilling" column="EXPORTEDFORBILLING" not-null="true"/>
</class>
</hibernate-mapping>
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.nsn.idtv.ibilling.trax.dto.EventDto" table="EVENTS">
<cache usage="nonstrict-read-write" region="com.nsn.idtv.ibilling.trax.dto.EventDto"/>
<composite-id class="com.nsn.idtv.ibilling.repository.event.HibernateEventDao$EventPK" mapped="true">
<key-many-to-one name="provider" column="PROVIDERID" />
<key-property name="eventId" column="EVENTID" />
</composite-id>
<property name="price" column="PRICE" />
<property name="displayName" column="DISPLAYNAME" />
<property name="vat" column="VAT" />
<property name="startTime" column="STARTTIME" />
<property name="endTime" column="ENDTIME" />
<property name="deleted" column="DELETED" />
</class>
</hibernate-mapping>
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.nsn.idtv.ibilling.trax.dto.ProviderDto" table="PROVIDERS">
<id name="providerId" column="PROVIDERID" />
<property name="name" column="DISPLAYNAME" />
<property name="deleted" column="DELETED" />
</class>
</hibernate-mapping>
Here are the respective classes:
Code:
package com.nsn.idtv.ibilling.domain;
import java.sql.Timestamp;
import java.util.Date;
import com.nsn.idtv.ibilling.trax.dto.EventDto;
import com.nsn.idtv.ibilling.trax.dto.ProviderDto;
public class Transaction {
private long transactionId;
private EventDto event;
private String mac;
private float price;
private Timestamp timestamp;
private String selectionId;
private String textString;
private boolean exportedForPostProcessing;
private boolean exportedForBilling;
private String urlpath;
/**
* Constructor for lookups from the database
*/
public Transaction() {
this.event = new EventDto();
this.event.setProvider(new ProviderDto());
this.timestamp = new Timestamp(new Date().getTime()); // now
this.exportedForBilling = false;
this.exportedForPostProcessing = false;
}
/**
* Contstructor insert in the database: for the arguments that have to be provided (not null in db)
* @param providerId
* @param mac
* @param eventId
* @param price
*/
public Transaction(String providerId, String mac,
String eventId, float price, String urlpath) {
this();
this.mac = mac;
event.getProvider().setProviderId(providerId);
event.setEventId(eventId);
this.price=price;
this.urlpath = urlpath;
}
public long getTransactionId() {
return transactionId;
}
public void setTransactionId(long transactionId) {
this.transactionId = transactionId;
}
public String getMac() {
return mac;
}
public void setMac(String mac) {
this.mac = mac;
}
public EventDto getEvent() {
return event;
}
public void setEvent(EventDto event) {
this.event = event;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public Timestamp getTimestamp() {
return timestamp;
}
public void setTimestamp(Timestamp timestamp) {
this.timestamp = timestamp;
}
public String getSelectionId() {
return selectionId;
}
public void setSelectionId(String selectionId) {
this.selectionId = selectionId;
}
public String getTextString() {
return textString;
}
public void setTextString(String textString) {
this.textString = textString;
}
public boolean getExportedForPostProcessing() {
return exportedForPostProcessing;
}
public void setExportedForPostProcessing(boolean exportedForPostProcessing) {
this.exportedForPostProcessing = exportedForPostProcessing;
}
public boolean getExportedForBilling() {
return exportedForBilling;
}
public void setExportedForBilling(boolean exportedForBilling) {
this.exportedForBilling = exportedForBilling;
}
public String getUrlpath() {
return urlpath;
}
public void setUrlpath(String urlpath) {
this.urlpath = urlpath;
}
}
Code:
package com.nsn.idtv.ibilling.trax.dto;
import java.io.Serializable;
import java.sql.Timestamp;
public class EventDto implements Serializable {
private static final long serialVersionUID = -1709006320371554848L;
private ProviderDto provider;
private String eventId;
private String displayName;
private float price;
private String vat;
private Timestamp startTime;
private Timestamp endTime;
private boolean deleted;
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getVat() {
return vat;
}
public void setVat(String vat) {
this.vat = vat;
}
public ProviderDto getProvider() {
return provider;
}
public void setProvider(ProviderDto provider) {
this.provider = provider;
}
public String getEventId() {
return eventId;
}
public void setEventId(String eventid) {
this.eventId = eventid;
}
public Timestamp getStartTime() {
return startTime;
}
public void setStartTime(Timestamp startTime) {
this.startTime = startTime;
}
public Timestamp getEndTime() {
return endTime;
}
public void setEndTime(Timestamp endTime) {
this.endTime = endTime;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("{eventId=").append(eventId);
buff.append(",provider=").append(provider.toString());
buff.append(",displayName=").append(displayName);
buff.append(",price=").append(price);
buff.append(",vat=").append(vat);
buff.append(",startTime=").append(startTime != null ? startTime.toString():"null");
buff.append(",endTime=").append(endTime != null ? endTime.toString():"null");
buff.append(",deleted=").append(deleted);
buff.append("}");
return buff.toString();
//return "provider [".concat(eventId).concat("] ").concat(displayName);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (deleted ? 1231 : 1237);
result = prime * result
+ ((displayName == null) ? 0 : displayName.hashCode());
result = prime * result + ((endTime == null) ? 0 : endTime.hashCode());
result = prime * result + ((eventId == null) ? 0 : eventId.hashCode());
result = prime * result + Float.floatToIntBits(price);
result = prime * result
+ ((provider == null) ? 0 : provider.hashCode());
result = prime * result
+ ((startTime == null) ? 0 : startTime.hashCode());
result = prime * result + ((vat == null) ? 0 : vat.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final EventDto other = (EventDto) obj;
if (deleted != other.deleted)
return false;
if (displayName == null) {
if (other.displayName != null)
return false;
} else if (!displayName.equals(other.displayName))
return false;
if (endTime == null) {
if (other.endTime != null)
return false;
} else if (!endTime.equals(other.endTime))
return false;
if (eventId == null) {
if (other.eventId != null)
return false;
} else if (!eventId.equals(other.eventId))
return false;
if (Float.floatToIntBits(price) != Float.floatToIntBits(other.price))
return false;
if (provider == null) {
if (other.provider != null)
return false;
} else if (!provider.equals(other.provider))
return false;
if (startTime == null) {
if (other.startTime != null)
return false;
} else if (!startTime.equals(other.startTime))
return false;
if (vat == null) {
if (other.vat != null)
return false;
} else if (!vat.equals(other.vat))
return false;
return true;
}
}
Code:
package com.nsn.idtv.ibilling.trax.dto;
import java.io.Serializable;
public class ProviderDto implements Serializable {
private String providerId;
private String name;
private boolean deleted;
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("{providerId=").append(providerId);
buff.append(",name=").append(name);
buff.append(",deleted=").append(deleted);
buff.append("}");
return buff.toString();
//return "event [".concat(providerId).concat("] ").concat(name);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (deleted ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result
+ ((providerId == null) ? 0 : providerId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ProviderDto other = (ProviderDto) obj;
if (deleted != other.deleted)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (providerId == null) {
if (other.providerId != null)
return false;
} else if (!providerId.equals(other.providerId))
return false;
return true;
}
}
Finally: this is an event's PK class:
Code:
private static class EventPK implements java.io.Serializable {
private static final long serialVersionUID = -7293263010056587754L;
private ProviderDto provider;
private String eventId;
public EventPK() {
}
public EventPK(String providerId, String eventId) {
this.provider = new ProviderDto();
this.provider.setProviderId(providerId);
this.eventId = eventId;
}
public ProviderDto getProvider() {
return provider;
}
public void setProvider(ProviderDto provider) {
this.provider = provider;
}
public String getEventId() {
return eventId;
}
public void setEventId(String eventId) {
this.eventId = eventId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((eventId == null) ? 0 : eventId.hashCode());
result = prime * result
+ ((provider == null) ? 0 : provider.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final EventPK other = (EventPK) obj;
if (eventId == null) {
if (other.eventId != null)
return false;
} else if (!eventId.equals(other.eventId))
return false;
if (provider == null) {
if (other.provider != null)
return false;
} else if (!provider.equals(other.provider))
return false;
return true;
}
}
I've used a debugger to make sure every field (and certainly every mandatory field) of the transaction I'm trying to save is not null - still no success.
Why am I getting this exception?
Thanks!