jpa entity complex key error - exception

I need your help with my JPA problem.
Please look at the following entities and primary complex keys.
#Embeddable
public class BookingPK implements Serializable
{
private static final long serialVersionUID = 1L;
private String carrid;
private String connid;
private String bookid;
public String getcarrid()
{
return this.carrid;
}
public void setcarrid(String carrid)
{
this.carrid = carrid;
}
public String getconnid()
{
return this.connid;
}
public void setconnid(String connid)
{
this.connid = connid;
}
public String getbookid()
{
return this.bookid;
}
public void setbookid(String bookid)
{
this.bookid = bookid;
}
public int hashCode()
{
return (int) ( this.carrid.hashCode())
+(int) ( this.connid.hashCode())
+(int) ( this.bookid.hashCode());
}
public boolean equals(Object obj)
{
if (obj == this) return true;
if (!(obj instanceof Booking)) return false;
BookingPK pk = (BookingPK) obj;
return pk.carrid.equals(this.carrid)
&& pk.connid.equals(this.connid)
&& pk.bookid.equals(this.bookid);
}
#Entity
public class Booking
{
#EmbeddedId
private BookingPK bookingPrimaryKey;
private String CANCELLED;
public BookingPK getbookingPrimaryKey()
{
return this.bookingPrimaryKey;
}
public void setbookingPrimaryKey(BookingPK key)
{
this.bookingPrimaryKey = key;
}
public String getCANCELLED()
{
return this.CANCELLED;
}
public void setCANCELLED(String CANCELLED)
{
this.CANCELLED = CANCELLED;
}
}
#Embeddable
public class FlightPK implements Serializable
{
private static final long serialVersionUID = 1L;
private String carrid;
private String connid;
public String getcarrid()
{
return this.carrid;
}
public void setcarrid(String carrid)
{
this.carrid = carrid;
}
public String getconnid()
{
return this.connid;
}
public void setconnid(String connid)
{
this.connid = connid;
}
public int hashCode()
{
return (int) ( this.carrid.hashCode())
+(int) ( this.connid.hashCode());
}
public boolean equals(Object obj)
{
if (obj == this) return true;
if (!(obj instanceof Flight)) return false;
FlightPK pk = (FlightPK) obj;
return pk.carrid.equals(this.carrid)
&& pk.connid.equals(this.connid);
}
}
#Entity
public class Flight
{
#EmbeddedId
private FlightPK flightPrimaryKey;
private Booking bookedFlight;
public Booking getbookedFlight()
{
return this.bookedFlight;
}
public void setbookedFlight(Booking flight)
{
this.bookedFlight = flight;
}
public FlightPK getflightPrimaryKey()
{
return this.flightPrimaryKey;
}
public void setPRICE(FlightPK key)
{
this.flightPrimaryKey = key;
}
}
Whei i run my application to create DB tables i get the following exception:
Exception in thread "main" javax.persistence.PersistenceException: Exception [EclipseLink-0] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.IntegrityException
Descriptor Exceptions:
Exception [EclipseLink-48] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [FLIGHT.CONNID]. Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.OneToOneMapping[bookedFlight]
Descriptor: RelationalDescriptor(testik.Flight --> [DatabaseTable(FLIGHT)])
Exception [EclipseLink-48] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [FLIGHT.CARRID]. Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.OneToOneMapping[bookedFlight]
Descriptor: RelationalDescriptor(testik.Flight --> [DatabaseTable(FLIGHT)])
Runtime Exceptions:
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:517)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getDatabaseSession(EntityManagerFactoryDelegate.java:188)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getMetamodel(EntityManagerFactoryDelegate.java:591)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:506)
at org.odata4j.producer.jpa.JPAEdmGenerator.generateEdm(JPAEdmGenerator.java:95)
at org.odata4j.producer.jpa.JPAProducer.<init>(JPAProducer.java:91)
at com.mockservice.MockService.<init>(MockService.java:34)
at com.mockservice.MockService.main(MockService.java:51)
Caused by: Exception [EclipseLink-0] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.IntegrityException
Descriptor Exceptions:
Please advise what is wrong. I have already tried every thing but without success.
Regards,
Slavik.

The error occurs because you have multiple attributes mapping the same columns.
You model seems very confused. If connection and carrier are unique, then why does booking need another id? Or how can a flight have a single unique booking?
Personally I would not recommend using EmbeddedId, but an IdClass instead, and use #Id on your relationship.
You may also be able to use insertable/updateable=false on your join columns, but your model seems odd.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#JPA_2.0

Related

spring batch - how to pass dynamic list while application running to ListItemReader store it into database

I'm new to this Spring-Batch technology please help regarding how to pass dynamic list while application running to ListItemReader and store it to MySql DB.
Ex. I fetch some value from DB and do some calculation on that fetched data and i prepare one list and this new list to be pass to ListItemReader and store it into DB.
Thank you for the help.
Below are custom implementations of ListItemWriter and ListItemReader which lets you define a name property. This property is used as a key to store the list in the JobExecutionContext.
In your case, you can have 3 steps :
JDBCReader > ListItemWriter
Calculation Tasklet
ListItemReader > JDBCWriter
If your tasklet needs to get the lists, you can use the same way as below (ie. read/write the JobExecutionContext).
The reader :
public class CustomListItemReader<T> implements ItemReader<T>, StepExecutionListener {
private String name;
private List<T> list;
#Override
public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if (list != null && !list.isEmpty()) {
return list.remove(0);
}
return null;
}
#Override
public void beforeStep(StepExecution stepExecution) {
list = (List<T>) stepExecution.getJobExecution().getExecutionContext().get(name);
}
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
public void setName(String name) {
this.name = name;
}
}
The writer :
public class CustomListItemWriter<T> implements ItemWriter<T>, StepExecutionListener {
private String name;
private List<T> list = new ArrayList<T>();
#Override
public void write(List<? extends T> items) throws Exception {
for (T item : items) {
list.add(item);
}
}
#Override
public void beforeStep(StepExecution stepExecution) {}
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
stepExecution.getJobExecution().getExecutionContext().put(name, list);
return null;
}
public void setName(String name) {
this.name = name;
}
}

DAO MVC: why my class is NOT POJO

I use DAO MVC, and I after some googling I consider to store some variables as Enum in java and String in MySQL. So I create in Item.java (that will be persist into Item table) static initialization and static methods to convert Enum into String and vise versa.
But someone said me that after this static initialization and static methods my Item.java class became NOT POJO.
Question:
Why it became NOT POJO?
And if I'll make those methods not static Item.java class will be POJO?
EDITED: MY code:
package model;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
public class Order {
public enum OrderStatus {
NOT_REVIEWED,
APPROVED,
REJECTED,
RETURNED
}
// ==================
// = Transient =
// ==================
private static final Map<String, OrderStatus> convertStringToOrderStatusMap = new HashMap<String, OrderStatus>(3);
private static final Map<OrderStatus, String> convertOrderStatusToStringMap = new EnumMap<OrderStatus, String>(OrderStatus.class);
static {
convertStringToOrderStatusMap.put("not reviewed", OrderStatus.NOT_REVIEWED);
convertStringToOrderStatusMap.put("approved", OrderStatus.APPROVED);
convertStringToOrderStatusMap.put("rejected", OrderStatus.REJECTED);
convertStringToOrderStatusMap.put("returned", OrderStatus.RETURNED);
convertOrderStatusToStringMap.put(OrderStatus.NOT_REVIEWED, "not reviewed");
convertOrderStatusToStringMap.put(OrderStatus.APPROVED, "approved");
convertOrderStatusToStringMap.put(OrderStatus.REJECTED, "rejected");
convertOrderStatusToStringMap.put(OrderStatus.RETURNED, "returned");
}
// ==================
// = Attributes =
// ==================
private Integer orderId; //Primary key
private OrderStatus status;
private Integer reimbursement;
private String firstName;
private String secondName;
private String passportData;
private String pickUpDate;
private String dropOffDate;
//java.util.Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2011-05-18 16:29:31");
private String customerCell;
private String customerAddress;
// ==================
// = Foreign Keys =
// ==================
private User user;
private Car car;
// ==================
// = Public methods =
// ==================
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public String getStatus() {
return convertOrderStatusToString(status);
}
public void setStatus(OrderStatus status) {
this.status = status;
}
public Integer getReimbursement() {
return this.reimbursement;
}
public void setReimbursement(Integer value) {
this.reimbursement = value;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSecondName() {
return secondName;
}
public void setSecondName(String secondName) {
this.secondName = secondName;
}
public String getPassportData() {
return passportData;
}
public void setPassportData(String passportData) {
this.passportData = passportData;
}
public String getPickUpDate() {
return pickUpDate;
}
public void setPickUpDate(String pickUpDate) {
this.pickUpDate = pickUpDate;
}
public String getDropOffDate() {
return dropOffDate;
}
public void setDropOffDate(String dropOffDate) {
this.dropOffDate = dropOffDate;
}
public String getCustomerCell() {
return customerCell;
}
public void setCustomerCell(String customerCell) {
this.customerCell = customerCell;
}
public String getCustomerAddress() {
return customerAddress;
}
public void setCustomerAddress(String customerAddress) {
this.customerAddress = customerAddress;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public static OrderStatus converStringToOrderStatus(String status) {
return convertStringToOrderStatusMap.get(status);
}
public static String convertOrderStatusToString(OrderStatus status) {
return convertOrderStatusToStringMap.get(status);
}
}
Because a Plain Old Java Object only has data. Adding logic and methods means that it's no longer Plain Old Java Object.
That doesn't necessarily make it a bad thing, but you might be able to refactor the logic out into a class of it's own.
Lets ignore POJO.
What they mean is Service Oriented vs Domain Driven.
Service Oriented follows strict separation of behavior from state. They call POJOs data objects which are essentially glorified structs. Thus you would put the static methods in the Service. In fact you probably wouldn't even want the methods static as that is also against the service oriented approach (see dependency injection and evil singleton).
Domain Driven follows the idea of classic OOP (e.g. Rails Active Record) in which they do believe its OK to put behavior in their POJOs. Consequently because state + behavior are coupled there is only one implementation and thus static methods in the domain object are OK.
If your going the DAO route your most likely doing Service Oriented. My opinion is if your going to do the DAO POJO route you should use immutable objects (shameless plug) for those data objects.
Finally putting an inline enum into a class from my knowledge does not violate any definition of POJO. That being said you should know about #Enumerated since your using JPA.

Entity Framework type case generic in predicate

I am working on updating to a more manageable repository pattern in my MVC 4 project that uses Entity Framework code first. I've integrated a generic base repository class that will do basic CRUD operations so I don't have to implement these in each repository I create. I have ran into an issue where my All method needs to filter there query by a deleted flag if the entity is a type of TrackableEntity. Since the Entity is generic in the base repository I am attempting to cast is to a type of TrackableEntity in the where which just results in the following error message.
The 'TypeAs' expression with an input of type 'NameSpace.Models.ClientFormField' and a check of type 'NameSpace.Models.TrackableEntity' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.
This error makes complete since and I understand why the code I have is not working but I am trying to find a way to filter out deleted items without having to override this method in all of my repositories. The code I have for my All method is below.
public virtual IEnumerable<T> All()
{
if (typeof(T).IsSubclassOf(typeof(TrackableEntity)))
return dbSet.Where(e => !(e as TrackableEntity).IsDeleted).ToList();
return dbSet.ToList();
}
I know that I can do the following
public virtual IEnumerable<T> All(Expression<Func<T, bool>> predicate = null)
{
if (predicate != null)
return dbSet.Where(predicate).IsDeleted).ToList();
return dbSet.ToList();
}
And then add this to all of my repositories
public override IEnumerable<CaseType> All(Expression<Func<CaseType,bool>> predicate = null)
{
if (predicate == null)
predicate = e => !e.IsDeleted;
return base.All(predicate);
}
The problem I have with this is that I am duplicating code, this is basically a copy and paste into all of my repositories which defeats the purpose of changing to this new repository pattern. I made the switch to end duplicated code in my repositories.
Here is an example of one of my entities.
public class CaseType : TrackableEntity, IValidatableObject
{
public int Id { get; set; }
public string Name { get; set; }
public bool InUse { get; set; }
public bool IsValid { get { return !this.Validate(null).Any(); } }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (String.IsNullOrEmpty(Name))
yield return new ValidationResult("Case Type name cannot be blank", new[] { "Name" });
//Finish Validation Rules
}
}
And the TrackableEntity
public abstract class TrackableEntity
{
public bool Active { get; set; }
public bool IsDeleted { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
}
Any help on this would be much appreciated.
I finally got a solution working that I am happy with. I ended up making 2 generic repositories. One that is the base repository which deals with all of the calls to the database for my BaseEntity which all entities inherit from. Then I made my 2nd generic repo which is inherits BaesEntity and overrides a few methods to handle the needs of my TrackableEntities. In the end this does what I want by handling the filtering of soft deleted items from within the repo and also gives me more flexibility with the TrackableEntity.
BaseRepository -
public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity
{
private readonly IAppDb _db;
private readonly IDbSet<T> _dbSet;
public BaseRepository(IAppDb db)
{
_db = db;
_dbSet = Lwdb.Set<T>();
}
protected IAppDb Lwdb
{
get { return _db; }
}
#region IBaseRepository<T> Members
public virtual T GetById(int id)
{
return _dbSet.Find(id);
}
public virtual T Add(T entity)
{
_dbSet.Add(entity);
_db.Commit();
return entity;
}
public virtual bool Any(Expression<Func<T, bool>> expression)
{
return _dbSet.Any(expression);
}
public virtual void Delete(T entity)
{
_dbSet.Remove(entity);
_db.Commit();
}
public virtual IEnumerable<T> All()
{
return _dbSet.ToList();
}
public virtual T Update(T entity, bool attachOnly = false)
{
_dbSet.Attach(entity);
_db.SetModified(entity);
if (!attachOnly) _db.Commit();
return entity;
}
#endregion
protected User GetCurrentUser()
{
return
_db.Set<User>().Find(HttpContext.Current != null ? ((User) HttpContext.Current.Session["User"]).Id : 1);
}
BaseTrackableEntityRepository -
public class BaseTrackableEntityRepository<T> : BaseRepository<T>, IBaseTrackableEntityRepository<T>
where T : TrackableEntity
{
private readonly IAppDb _db;
private readonly IDbSet<T> _teDB;
public BaseTrackableEntityRepository(IAppDb db)
: base(db)
{
_db = db;
_teDB = _db.Set<T>();
}
#region IBaseTrackableEntityRepository<T> Members
public virtual T SetDeleteFlag(int id)
{
var entity = _teDB.Find(id);
if (entity == null) return null; //throw exception
entity.IsDeleted = true;
entity.DateModified = DateTime.Now;
entity.ModifiedBy = GetCurrentUser();
return Update(entity);
}
public override IEnumerable<T> All()
{
return _teDB.Where(e => !e.IsDeleted).ToList();
}
public override T Add(T entity)
{
var curUser = GetCurrentUser();
entity.CreatedBy = curUser;
entity.ModifiedBy = curUser;
entity.DateCreated = DateTime.Now;
entity.DateModified = DateTime.Now;
entity.Active = true;
entity.IsDeleted = false;
_teDB.Add(entity);
_db.Commit();
return entity;
}
public override T Update(T entity, bool attachOnly = false)
{
InsertTeData(ref entity);
entity.ModifiedBy = GetCurrentUser();
entity.DateModified = DateTime.Now;
_teDB.Attach(entity);
_db.SetModified(entity);
if (!attachOnly) _db.Commit();
return entity;
}
public virtual T SetStatus(int id, bool status)
{
var entity = _teDB.Find(id);
if (entity == null) return null;
entity.Active = status;
return Update(entity);
}
#endregion
private void InsertTeData(ref T entity)
{
if (entity == null || entity == null) return;
var dbEntity = GetById(entity.Id);
if (dbEntity == null) return;
_db.Detach(dbEntity);
entity.CreatedBy = dbEntity.CreatedBy;
entity.DateCreated = dbEntity.DateCreated;
entity.ModifiedBy = dbEntity.ModifiedBy;
entity.DateModified = dbEntity.DateModified;
}

Hibernate MappingException while using annotation #Inheritance with MySql

I'am using Hibernate framework 3.6.10.Final and MySql. I'am getting
Exception in thread "main" org.hibernate.MappingException: Cannot use identity column key generation with mapping for: org.koushik.javabrains.dto.Vehicle
when am including #Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) in vehicle class. It's working fine with out this annotation.
Vehicle.java is my base class:
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Vehicle
{
#Id
#GeneratedValue
private int vehicleId;
private String vehicleName;
public int getVehicleId() {
return vehicleId;
}
public void setVehicleId(int vehicleId) {
this.vehicleId = vehicleId;
}
public String getVehicleName() {
return vehicleName;
}
public void setVehicleName(String vehicleName) {
this.vehicleName = vehicleName;
}
}
TwoWheeler.java:
#Entity
public class TwoWheeler extends Vehicle {
private String SteeringHandle;
public String getSteeringHandle() {
return SteeringHandle;
}
public void setSteeringHandle(String steeringHandle) {
SteeringHandle = steeringHandle;
}
}
FourWheeler.java:
#Entity
public class FourWheeler extends Vehicle {
private String SteeringWheel;
public String getSteeringWheel() {
return SteeringWheel;
}
public void setSteeringWheel(String steeringHandle) {
SteeringWheel = steeringHandle;
}
}
My main class:
public class HibernateTest {
public static void main(String[] args)
{
Vehicle vehicle = new Vehicle();
vehicle.setVehicleName("audi"+(int)(Math.random() * 100) + 1);
TwoWheeler bike = new TwoWheeler();
bike.setVehicleName("bike");
bike.setSteeringHandle("Bike SteeringHandle");
FourWheeler car = new FourWheeler();
car.setVehicleName("car");
car.setSteeringWheel("Car SteeringHandle");
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(vehicle);
session.save(bike);
session.save(car);
session.getTransaction().commit();
session.close();
}
}
And when am running am getting following error:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Exception in thread "main" org.hibernate.MappingException: Cannot use identity column key generation with mapping for: org.koushik.javabrains.dto.Vehicle
at org.hibernate.persister.entity.UnionSubclassEntityPersister.(UnionSubclassEntityPersister.java:90)
at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:90)
at org.hibernate.impl.SessionFactoryImpl.(SessionFactoryImpl.java:286)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1872)
at org.koushik.hibernate.HibernateTest.main(HibernateTest.java:26)
if you use TABLE_PER_CLASS, you have to use this ID generation strategy: #GeneratedValue(strategy
= GenerationType.TABLE)
Vehicle.java
#Entity
#Table(name="vehicle")
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Vehicle
{
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
#Column(name="vehicle_id")
private int vehicleId;
#Column(name="vehicle_name")
private String vehicleName;
public int getVehicleId() {
return vehicleId;
}
public void setVehicleId(int vehicleId) {
this.vehicleId = vehicleId;
}
public String getVehicleName() {
return vehicleName;
}
public void setVehicleName(String vehicleName) {
this.vehicleName = vehicleName;
}
}

Hibernate n:m extractHashCode throws NullPointerException

I get the following exception while inserting an object with hibernate. Reading from the database works like a charm. I use MySQL 5.5 as database provider and hibernate 3.6.5.
I have the following database schema:
cell(id,cellid,lac,mcc,mnc,insertTime)
location(id,latitude,longitude,altitude,accuracy,heading,hdop,vdop,pdop,insertTime)
cellatlocation(servingCell,neighbourCell,location,signalStrength,insertTime)
where id in cell and location are primary keys and servingCell,neighbourCell and location is the composite primary key in cellatlocation.
java.lang.NullPointerException
at org.hibernate.type.descriptor.java.AbstractTypeDescriptor.extractHashCode(AbstractTypeDescriptor.java:88)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:196)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:191)
at org.hibernate.type.EntityType.getHashCode(EntityType.java:325)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:222)
at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:126)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:70)
at org.hibernate.engine.StatefulPersistenceContext.getDatabaseSnapshot(StatefulPersistenceContext.java:286)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:211)
at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:531)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:103)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:685)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:673)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:345)
at $Proxy17.saveOrUpdate(Unknown Source)
The classes I want to insert:
Cell.java
#Entity
#Table(name = "cell", catalog = "crisis")
public class Cell implements Serializable {
private static final long serialVersionUID = -8532796958180260393L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Integer mnc;
private Integer mcc;
private Long cellid;
private Integer lac;
#org.hibernate.annotations.Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime insertTime;
#OneToMany(mappedBy = "pk.servingCell")
private List<CellAtLocation> cellAtLocation = new LinkedList<CellAtLocation>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getMnc() {
return mnc;
}
public void setMnc(Integer mnc) {
this.mnc = mnc;
}
public Integer getMcc() {
return mcc;
}
public void setMcc(Integer mcc) {
this.mcc = mcc;
}
public Long getCellid() {
return cellid;
}
public void setCellid(Long cellid) {
this.cellid = cellid;
}
public Integer getLac() {
return lac;
}
public void setLac(Integer lac) {
this.lac = lac;
}
public DateTime getInsertTime() {
return insertTime;
}
public void setInsertTime(DateTime insertTime) {
this.insertTime = insertTime;
}
public List<CellAtLocation> getCellAtLocation() {
return cellAtLocation;
}
public void setCellAtLocation(List<CellAtLocation> cellAtLocation) {
this.cellAtLocation = cellAtLocation;
}
}
Location.java
#Entity
#Table(name = "location", catalog = "crisis")
public class Location implements Serializable {
private static final long serialVersionUID = 2197290868029835453L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Double latitude;
private Double longitude;
private Double altitude;
private Double accuracy;
private Double heading;
private Double hdop;
private Double vdop;
private Double pdop;
#org.hibernate.annotations.Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime insertTime;
#OneToMany(mappedBy = "pk.location")
private List<CellAtLocation> cellAtLocation = new LinkedList<CellAtLocation>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Double getLatitude() {
return latitude;
}
public void setLatitude(Double latitude) {
this.latitude = latitude;
}
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
this.longitude = longitude;
}
public Double getAltitude() {
return altitude;
}
public void setAltitude(Double altitude) {
this.altitude = altitude;
}
public Double getAccuracy() {
return accuracy;
}
public void setAccuracy(Double accuracy) {
this.accuracy = accuracy;
}
public Double getHeading() {
return heading;
}
public void setHeading(Double heading) {
this.heading = heading;
}
public Double getHdop() {
return hdop;
}
public void setHdop(Double hdop) {
this.hdop = hdop;
}
public Double getVdop() {
return vdop;
}
public void setVdop(Double vdop) {
this.vdop = vdop;
}
public Double getPdop() {
return pdop;
}
public void setPdop(Double pdop) {
this.pdop = pdop;
}
public DateTime getInsertTime() {
return insertTime;
}
public void setInsertTime(DateTime insertTime) {
this.insertTime = insertTime;
}
public List<CellAtLocation> getCellAtLocation() {
return cellAtLocation;
}
public void setCellAtLocation(List<CellAtLocation> cellAtLocation) {
this.cellAtLocation = cellAtLocation;
}
}
CellAtLocation.java
#Entity
#Table(name = "cellatlocation", catalog = "crisis")
#AssociationOverrides({ #AssociationOverride(name = "pk.servingCell", joinColumns = #JoinColumn(name = "servingCell")),
#AssociationOverride(name = "pk.neighbourCell", joinColumns = #JoinColumn(name = "neighbourCell")),
#AssociationOverride(name = "pk.location", joinColumns = #JoinColumn(name = "location")) })
public class CellAtLocation implements Serializable {
private static final long serialVersionUID = -4440795783726362367L;
private CellAtLocationPk pk = new CellAtLocationPk();
private Integer signalStrength;
#EmbeddedId
private CellAtLocationPk getPk() {
return pk;
}
#SuppressWarnings("unused")
private void setPk(CellAtLocationPk pk) {
this.pk = pk;
}
#Transient
public Cell getServingCell() {
return getPk().getServingCell();
}
public void setServingCell(Cell cell) {
getPk().setServingCell(cell);
}
#Transient
public Cell getNeighbourCell() {
return getPk().getNeighbourCell();
}
public void setNeighbourCell(Cell cell) {
getPk().setNeighbourCell(cell);
}
#Transient
public Location getLocation() {
return getPk().getLocation();
}
public void setLocation(Location location) {
getPk().setLocation(location);
}
public Integer getSignalStrength() {
return signalStrength;
}
public void setSignalStrength(Integer signalStrength) {
this.signalStrength = signalStrength;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
CellAtLocation that = (CellAtLocation) o;
if (getPk() != null ? !getPk().equals(that.getPk()) : that.getPk() != null)
return false;
return true;
}
public int hashCode() {
return (getPk() != null ? getPk().hashCode() : 0);
}
}
and finally the primary key mapping itself CellAtLocationPk.java
#Embeddable
public class CellAtLocationPk implements Serializable {
private static final long serialVersionUID = 5286485161491158083L;
private Cell servingCell;
private Cell neighbourCell;
private Location location;
#ManyToOne
public Cell getServingCell() {
return servingCell;
}
public void setServingCell(Cell servingCell) {
this.servingCell = servingCell;
}
#ManyToOne
public Cell getNeighbourCell() {
return neighbourCell;
}
public void setNeighbourCell(Cell neighbourCell) {
this.neighbourCell = neighbourCell;
}
#ManyToOne
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
CellAtLocationPk that = (CellAtLocationPk) o;
if (servingCell != null ? !servingCell.equals(that.servingCell) : that.servingCell != null)
return false;
if (neighbourCell != null ? !neighbourCell.equals(that.neighbourCell) : that.neighbourCell != null)
return false;
if (location != null ? !location.equals(that.location) : that.location != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (servingCell != null ? servingCell.hashCode() : 0);
result = 31 * result + (neighbourCell != null ? neighbourCell.hashCode() : 0);
result = 31 * result + (location != null ? location.hashCode() : 0);
return result;
}
}
The problem is that hibernate is trying to save the relationship object, CellAtLocation instance, while the children objects, Cell and/or Location instances are not yet persisted. Thus, children objects don't have generated ids associated with them and therefore hibernate can not compute the hash for them.
Before trying to save CellAtLocation instance, try saving the children objects first by calling saveOrUpdate method on them.
For anyone also dealing with this issue, it occurred in my case simply because I did not have an open and active transaction. The stack trace did not point directly to this being the issue but can be explained as follows:
The parent item was being persisted in the cache and hibernate simply accepted the parent not having an actual ID. If we could have somehow called flush() on our connection we would have then been notified of the non-existent transaction. Instead, when the child item was to be persisted the parent's ID did not TRULY exist. When hibernate went to get the parent's hashed id for the purpose of saving the child, the NPE was thrown.
I had the same problem and figured out that the way to properly map embedded ids is by using #Embeddable, #EmbeddedId and #MapsId (which is the one missing in the problem code). The docs from #MapsId annotation states an example that fixes this issue:
Example:
// parent entity has simple primary key
#Entity
public class Employee {
#Id
private long employeeId;
private String name;
...
}
// dependent entity uses EmbeddedId for composite key
#Embeddable
public class DependentId {
private String name;
private long employeeId; // corresponds to primary key type of Employee
}
#Entity
public class Dependent {
#EmbeddedId
private DependentId dependentId;
...
#MapsId("employeeId") // maps the employeeId attribute of embedded id
#ManyToOne
private Employee employee;
}
This is the proper way to fix the issue. This way, you wouldn't need to save the entities separately (which is not a good practice). Instead, hibernate will manage the entire transaction for you by mapping the generated ids properly.
Hope this helps for anyone having this issue in the future.
Cheers,
In my case, found out that one primary key in a foreign key table has not set. Only the fields that implement hashcode int the table were set.
I too found the problem to be that hibernate is trying to save the relationship/parent object, while the child object instances are not yet persisted. I solved it by setting child object Ids to 0 and hibernate picked up from there without having to save the child objects manually.
Hope this helps.