I am using postgresql with springboot. So whenever I am using post method to add a new detail in my table instead of autoincrementing id it's going from 1 to 3. It's taking alternate values rather than consecutive values. I have given following properties and then created table:
spring.jpa.hibernate.ddl-auto=create
Didn't create the table manually. What is the reason for this error? This is my entity class.
#Entity
#Table(name = "NORTHBOUND_SUBSCRIPTION")
public class NBSubscription {
#Id
#GeneratedValue
#Column(name = "nb_id")
private Long nbId;
#Column(name = "DEVICE_FILTER")
private String deviceFilter;
#Column(name = "INTERFACE_FILTER")
private String interfaceFilter;
#ManyToOne
#JoinColumn(name="subscriber_id", referencedColumnName="SUBSCRIBER_ID")
private Subscriber subscriber;
#OneToOne
#JoinColumn(name="sensor_group_id", referencedColumnName="ID")
private SensorGroup sensorGroup;
#Column(name = "EVENT_TYPE")
private String eventType;
#Column(name = "SAMPLING_INTERVAL")
private Integer samplingInterval;
#Column(name = "CREATEAT")
#DateTimeFormat(pattern = "dd-MM-yyyy HH:mm")
private Timestamp createAt;
#Column(name = "MODIFIEDAT")
#DateTimeFormat(pattern = "dd-MM-yyyy HH:mm")
private Timestamp modifiedAt;
#Column(name = "CREATEDBY")
private String createdBy;
#Column(name = "MODIFIEDBY")
private String modifiedBy;
#Column(name = "mark_deletion")
private String markDeletion;
public NBSubscription() {
super();
}
public NBSubscription(Subscriber subscriber, SensorGroup sensorGroup) {
super();
this.subscriber = subscriber;
this.sensorGroup = sensorGroup;
}
public Long getNbId() {
return nbId;
}
public void setNbId(Long nbId) {
this.nbId = nbId;
}
public String getDeviceFilter() {
return deviceFilter;
}
public void setDeviceFilter(String deviceFilter) {
this.deviceFilter = deviceFilter;
}
public String getInterfaceFilter() {
return interfaceFilter;
}
public void setInterfaceFilter(String interfaceFilter) {
this.interfaceFilter = interfaceFilter;
}
#JsonIgnore
public Subscriber getSubscriber() {
return subscriber;
}
public void setSubscriber(Subscriber subscriber) {
this.subscriber = subscriber;
}
public SensorGroup getSensorGroup() {
return sensorGroup;
}
public void setSensorGroup(SensorGroup sensorGroup) {
this.sensorGroup = sensorGroup;
}
public Integer getSamplingInterval() {
return samplingInterval;
}
public void setSamplingInterval(Integer samplingInterval) {
this.samplingInterval = samplingInterval;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public Timestamp getCreateAt() {
return createAt;
}
public void setCreateAt(Timestamp createAt) {
this.createAt = createAt;
}
public Timestamp getModifiedAt() {
return modifiedAt;
}
public void setModifiedAt(Timestamp modifiedAt) {
this.modifiedAt = modifiedAt;
}
public String getMarkDeletion() {
return markDeletion;
}
public void setMarkDeletion(String markDeletion) {
this.markDeletion = markDeletion;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public String getModifiedBy() {
return modifiedBy;
}
public void setModifiedBy(String modifiedBy) {
this.modifiedBy = modifiedBy;
}
Try this
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
if it doesn't work, try using the table sequence
#Id
#GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
Your autoincrement is implemented with a sequence, and by default entities share the same sequence, so the autoincrement values get spread across the entities.
You could assign each entity its own sequence. But be aware sequences don't participate in transactions. That means if you have a rollback there will be a break in the numbering. Occasional gaps are not avoidable.
If you are making this sequence visible to users and they expect the numbering to be contiguous, my advice is to not use a sequence for that, and keep the user-visible counter in a field separate from the id. If it is visible to users, then at some point it will need to change, and you can't change ids.
Related
I have a next question: while working with Hibernate 3.3.0 run into a situation when I have two tables with one-to-many relationships and I need to get the list of parents. In each entity must be filled the several fields from the parent table and a list of all children mapped in the parent. For the easiest understanding, I give an example. I have two tables with one-to-many relationships: parent is "recipients" and child is "requisites". And I have two classes whose objects are the rows of these tables. Class for the table of recipients:
#Entity
#Table(name = "recipients")
#JsonFilter(value = "recipientsFilter")
public class POJORecipient implements POJO {
private static final long serialVersionUID = 4436819032452218525L;
#Id
#Column
private long id;
#Version
#Column
private long version;
#Column(name = "client_id")
private long clientId;
#Column
private String inn;
#Column
private String name;
#Column(name = "rcpt_country_code")
private String rcptCountryCode;
#Column(name = "rcpt_passp_ser")
private String rcptPasspSer;
#Column(name = "rcpt_passp_num")
private String rcptPasspNum;
#OneToMany(mappedBy = "recipient", fetch = FetchType.LAZY)
#JsonManagedReference
private Set<POJORequisite> requisites = new HashSet<>();
public POJORecipient(){}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public long getClientId() {
return clientId;
}
public void setClientId(long clientId) {
this.clientId = clientId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInn() {
return inn;
}
public void setInn(String inn) {
this.inn = inn;
}
public String getRcptCountryCode() {
return rcptCountryCode;
}
public void setRcptCountryCode(String rcptCountryCode) {
this.rcptCountryCode = rcptCountryCode;
}
public String getRcptPasspSer() {
return rcptPasspSer;
}
public void setRcptPasspSer(String rcptPasspSer) {
this.rcptPasspSer = rcptPasspSer;
}
public String getRcptPasspNum() {
return rcptPasspNum;
}
public void setRcptPasspNum(String rcptPasspNum) {
this.rcptPasspNum = rcptPasspNum;
}
public Set<POJORequisite> getRequisites() {
return requisites;
}
public void setRequisites(Set<POJORequisite> requisites) {
this.requisites = requisites;
}
}
and for requisites table:
#Entity
#Table(name = "requisites")
public class POJORequisite implements POJO {
private static final long serialVersionUID = -35864567359179960L;
#Id
#Column
private long id;
#Version
#Column
private long version;
#Column
private String bic;
#Column
private String bill;
#Column
private String comments;
#Column
private String note;
#ManyToOne
#JoinColumn(name = "recipient_id")
#JsonBackReference
private POJORecipient recipient;
public POJORequisite(){}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public String getBic() {
return bic;
}
public void setBic(String bic) {
this.bic = bic;
}
public String getBill() {
return bill;
}
public void setBill(String bill) {
this.bill = bill;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public POJORecipient getRecipient() {
return recipient;
}
public void setRecipient(POJORecipient recipient) {
this.recipient = recipient;
}
}
So, I want to select from the recipients only names and all mapped requisites. Consequently, after the selection, I will have a list of POJORecipient objects and in each object filled only the field "name" and set of POJORequisite objects.
As answer of my question I want to discover one of next: how can I do that with help HQL or Criteria API (the second variant is preferable), or understand it is impossible in Hibernate at all, or that this possibility appeared in later versions (also preferably with example). I'm trying to resolve this question for several months now and will be immensely grateful for any help. All clarifications and advices also will be so helpful. Thanks in advance!!!
I have these entities
NormalizedChannelStock.java
#Entity
#Table(name = "stocks")
public class NormalizedChannelStock {
#EmbeddedId
private NormalizedChannelStockId id;
#Column(name = "qty")
private int qty;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "channel_id", insertable = false, updatable = false)
private Channel channel;
#Column(name = "created_at", updatable = false)
private Timestamp createdAt;
#Column(name = "updated_at", updatable = false)
private Timestamp updatedAt;
public NormalizedChannelStockId getId() {
return id;
}
public void setId(NormalizedChannelStockId id) {
this.id = id;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
public Timestamp getCreatedAt() {
return createdAt;
}
public Timestamp getUpdatedAt() {
return updatedAt;
}
}
NormalizedChannelStockId.java
#Embeddable
public class NormalizedChannelStockId implements Serializable {
#Column(name = "channel_id")
private Integer channelId;
#Column(name = "sku")
private String sku;
public NormalizedChannelStockId() {
}
public NormalizedChannelStockId(Integer channelId, String sku) {
this.channelId = channelId;
this.sku = sku;
}
public Integer getChannelId() {
return channelId;
}
public void setChannelId(Integer channelId) {
this.channelId = channelId;
}
public String getSku() {
return sku;
}
public void setSku(String sku) {
this.sku = sku;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NormalizedChannelStockId that = (NormalizedChannelStockId) o;
return channelId.equals(that.channelId) &&
sku.equals(that.sku);
}
#Override
public int hashCode() {
return Objects.hash(channelId, sku);
}
}
Channel.java
#Entity
#Table(name = "channels")
public class Channel {
#Id
#Column(name = "channel_id")
private int channelId;
#Column(name = "channel_name")
private String channelName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "store_id", insertable = false, updatable = false)
private Store store;
public int getChannelId() {
return channelId;
}
public void setChannelId(int channelId) {
this.channelId = channelId;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public Store getStore() {
return store;
}
public void setStore(Store store) {
this.store = store;
}
}
The problem I'm facing is when I call
List<NormalizedChannelStock> entitiesToSave = ...
List<NormalizedChannelStock> savedEntities = normalizedChannelStockService.saveAll(entitiesToSave);
The returned entities in savedEntities have their Channel inner objects set to null, as well as their created_at and updated_at as shown
Is this normal behaviour? When I run a findAllById on the Repository, the Channels inside the Entities are loaded lazily properly, so I believe the entities are properly mapped in code. The problem is after I save them.
Does JPA not reload the entity after saving it?
As you stated in the comments you did not set those values before saving.
JPA does not load them for you. JPA pretty much doesn't load anything upon saving except the id if it is generated by the database.
A more common case of the same problem/limitation/misconceptions are bidirectional relationships: JPA pretty much ignores the not owning side and the developer has to make sure that both sides are in sync at all times.
You would have to refresh the entity yourself. Note that just loading it in the same transaction would have no effect because it would come from the 1st level cache and would be exactly the same instance.
I am new to JavaEE and I am having a problem with persisting a table that has foreign keys pointing to the primary key of another table using entity classes and ejb's entity manager. I am using Netbeans.
I have an entity called 'property' and have another entity called 'offer' which holds the foreign key pointing to the primary key of the property. So basically, the logic is that one property can have many offers. Therefore, I am trying to add new offers in the 'offer' table using the entity manager but I am not being able to do it. You can look at the code and see what I maybe missing.
Property entity:
#Entity
#Table(name = "PROPERTY")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Property.findAll", query = "SELECT p FROM Property p")})
public class Property implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "PROPERTYID")
private Integer propertyid;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 500)
#Column(name = "DESCRIPTION")
private String description;
#Size(max = 50)
#Column(name = "TYPE")
private String type;
#Column(name = "NUMBEROFBEDROOM")
private Integer numberofbedroom;
#Column(name = "NUMBEROFBATHROOM")
private Integer numberofbathroom;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 10)
#Column(name = "ISFURNISHED")
private String isfurnished;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 10)
#Column(name = "HASGARDEN")
private String hasgarden;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 20)
#Column(name = "SIZE")
private String size;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "PRICE")
private String price;
#Basic(optional = false)
#NotNull
#Column(name = "ENTEREDDATE")
#Temporal(TemporalType.DATE)
private Date entereddate;
#Basic(optional = false)
#NotNull
#Column(name = "ENTEREDTIME")
#Temporal(TemporalType.TIME)
private Date enteredtime;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "property")
private Paddress paddress;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "propertyid")
private Collection<Offer> offerCollection;
#JoinColumn(name = "PROPERTYOWNERID", referencedColumnName = "PROPERTYOWNERID")
#ManyToOne(optional = false)
private Propertyowner propertyownerid;
#JoinColumn(name = "REALESTATEAGENTID", referencedColumnName = "REALESTATEAGENTID")
#ManyToOne(optional = false)
private Realestateagent realestateagentid;
public Property() {
}
public Property(Integer propertyid) {
this.propertyid = propertyid;
}
public Property(Integer propertyid, String description, String isfurnished, String hasgarden, String size, String price, Date entereddate, Date enteredtime) {
this.propertyid = propertyid;
this.description = description;
this.isfurnished = isfurnished;
this.hasgarden = hasgarden;
this.size = size;
this.price = price;
this.entereddate = entereddate;
this.enteredtime = enteredtime;
}
public Integer getPropertyid() {
return propertyid;
}
public void setPropertyid(Integer propertyid) {
this.propertyid = propertyid;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getNumberofbedroom() {
return numberofbedroom;
}
public void setNumberofbedroom(Integer numberofbedroom) {
this.numberofbedroom = numberofbedroom;
}
public Integer getNumberofbathroom() {
return numberofbathroom;
}
public void setNumberofbathroom(Integer numberofbathroom) {
this.numberofbathroom = numberofbathroom;
}
public String getIsfurnished() {
return isfurnished;
}
public void setIsfurnished(String isfurnished) {
this.isfurnished = isfurnished;
}
public String getHasgarden() {
return hasgarden;
}
public void setHasgarden(String hasgarden) {
this.hasgarden = hasgarden;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public Date getEntereddate() {
return entereddate;
}
public void setEntereddate(Date entereddate) {
this.entereddate = entereddate;
}
public Date getEnteredtime() {
return enteredtime;
}
public void setEnteredtime(Date enteredtime) {
this.enteredtime = enteredtime;
}
public Paddress getPaddress() {
return paddress;
}
public void setPaddress(Paddress paddress) {
this.paddress = paddress;
}
#XmlTransient
public Collection<Offer> getOfferCollection() {
return offerCollection;
}
public void setOfferCollection(Collection<Offer> offerCollection) {
this.offerCollection = offerCollection;
}
public Propertyowner getPropertyownerid() {
return propertyownerid;
}
public void setPropertyownerid(Propertyowner propertyownerid) {
this.propertyownerid = propertyownerid;
}
public Realestateagent getRealestateagentid() {
return realestateagentid;
}
public void setRealestateagentid(Realestateagent realestateagentid) {
this.realestateagentid = realestateagentid;
}
public String dateToString()
{
DateFormat df = new SimpleDateFormat("dd/MM/yy");
return df.format(entereddate);
}
public String timeToString()
{
DateFormat df = new SimpleDateFormat("HH:mm:ss");
return df.format(enteredtime);
}
#Override
public int hashCode() {
int hash = 0;
hash += (propertyid != null ? propertyid.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Property)) {
return false;
}
Property other = (Property) object;
if ((this.propertyid == null && other.propertyid != null) || (this.propertyid != null && !this.propertyid.equals(other.propertyid))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.sushan.model.Property[ propertyid=" + propertyid + " ]";
}
}
EJB PropertyDAO:
#Stateless
public class PropertyDAO implements PropertyDAOLocal {
#PersistenceContext(unitName="RealEstateWebsite-ejbPU")
private EntityManager em;
#Override
public void AddProperty(Property property) {
em.persist(property);
}
#Override
public void EditProperty(Property property) {
em.merge(property);
}
#Override
public void DeleteProperty(int propertyId) {
em.remove(GetProperty(propertyId));
}
#Override
public List<Property> GetAllProperty() {
return em.createNamedQuery("Property.findAll").getResultList();
}
#Override
public Property GetProperty(int propertyId) {
return em.find(Property.class, propertyId);
}
#Override
public void EditPropertyAddress(Paddress propertyAddress) {
em.merge(propertyAddress);
}
}
Offer entity:
#Entity
#Table(name = "OFFER")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Offer.findAll", query = "SELECT o FROM Offer o")})
public class Offer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "OFFERID")
private Integer offerid;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "OFFERSTATUS")
private String offerstatus;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "ORIGINALOFFER")
private String originaloffer;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "OFFERINGBP")
private String offeringbp;
#Basic(optional = false)
#NotNull
#Column(name = "OFFEREDDATE")
#Temporal(TemporalType.DATE)
private Date offereddate;
#Basic(optional = false)
#NotNull
#Column(name = "OFFEREDTIME")
#Temporal(TemporalType.TIME)
private Date offeredtime;
#JoinColumn(name = "BUYERID", referencedColumnName = "BUYERID")
#ManyToOne(optional = false)
private Buyer buyerid;
#JoinColumn(name = "PROPERTYID", referencedColumnName = "PROPERTYID")
#ManyToOne(optional = false)
private Property propertyid;
public Offer() {
}
public Offer(Integer offerid) {
this.offerid = offerid;
}
public Offer(String offerstatus, String originaloffer, String offeringbp, Date offereddate, Date offeredtime, Buyer buyerid, Property propertyid) {
this.offerstatus = offerstatus;
this.originaloffer = originaloffer;
this.offeringbp = offeringbp;
this.offereddate = offereddate;
this.offeredtime = offeredtime;
this.buyerid = buyerid;
this.propertyid = propertyid;
}
public Integer getOfferid() {
return offerid;
}
public void setOfferid(Integer offerid) {
this.offerid = offerid;
}
public String getOfferstatus() {
return offerstatus;
}
public void setOfferstatus(String offerstatus) {
this.offerstatus = offerstatus;
}
public String getOriginaloffer() {
return originaloffer;
}
public void setOriginaloffer(String originaloffer) {
this.originaloffer = originaloffer;
}
public String getOfferingbp() {
return offeringbp;
}
public void setOfferingbp(String offeringbp) {
this.offeringbp = offeringbp;
}
public Date getOffereddate() {
return offereddate;
}
public void setOffereddate(Date offereddate) {
this.offereddate = offereddate;
}
public Date getOfferedtime() {
return offeredtime;
}
public void setOfferedtime(Date offeredtime) {
this.offeredtime = offeredtime;
}
public Buyer getBuyerid() {
return buyerid;
}
public void setBuyerid(Buyer buyerid) {
this.buyerid = buyerid;
}
public Property getPropertyid() {
return propertyid;
}
public void setPropertyid(Property propertyid) {
this.propertyid = propertyid;
}
#Override
public int hashCode() {
int hash = 0;
hash += (offerid != null ? offerid.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Offer)) {
return false;
}
Offer other = (Offer) object;
if ((this.offerid == null && other.offerid != null) || (this.offerid != null && !this.offerid.equals(other.offerid))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.sushan.model.Offer[ offerid=" + offerid + " ]";
}
EJB OfferDAO:
#Stateless
public class OfferDAO implements OfferDAOLocal {
#PersistenceContext(unitName="RealEstateWebsite-ejbPU")
EntityManager em;
#Override
public void EditOffer(Offer offer) {
em.merge(offer);
}
#Override
public List<Offer> GetAllOffer(int propertyId) {
return em.createNamedQuery("Offer.findByPropertyID").setParameter("propertyID", propertyId).getResultList();
}
#Override
public List<Offer> GetAllOffer() {
return em.createNamedQuery("Offer.findAll").getResultList();
}
#Override
public void Add(Offer offer) {
em.persist(offer);
}
}
Servlet that connects the JSP with the EJB:
String action = request.getParameter("action");
String currencyType = request.getParameter("ddlCurrencyType");
String amount = request.getParameter("offerAmount");
String propertyIdStr = request.getParameter("hdnbt");
if ("Offer".equalsIgnoreCase(action))
{
if ("".equals(action) & !"".equals(currencyType) & !"".equals(amount) & !"".equals(propertyIdStr))
{
DateFormat df = new SimpleDateFormat("dd/MM/yy");
DateFormat df1 = new SimpleDateFormat("HH:mm:ss");
Date currentDate = new Date();
Date currentTime = new Date();
int propertyId = Integer.parseInt(propertyIdStr);
try {
currentDate = df.parse(df.format(currentDate));
currentTime = df1.parse(df1.format(currentTime));
} catch (ParseException e) {
}
Buyer buyer = buyerDAO.GetBuyer(1);
Property property = propertyDAO.GetProperty(propertyId);
Offer offer = new Offer("Pending", amount, amount, currentDate, currentTime, buyer, property);
offerDAO.Add(offer);
}
else
{
}
}
request.setAttribute("allProperty", propertyDAO.GetAllProperty());
request.getRequestDispatcher("AdministerProperty.jsp").forward(request, response);
Am I missing something here? I have followed a tutorial which didn't have a foreign key guidance but tried to use my own logic to go around it but it didn't work. I cannot find a reliable source that uses the method similar to me. Most of the resources I find are for Hibernate but I am using EJB.
It seems that the method which retrieves the Property and the method that persists the Offer are run in a separate transactions (DAOs being the Stateless session beans).
That would mean that the Offer is populated and persisted with a detached Property, so the persistence provider is not aware of it.
Not sure why an exception is not raised but you would have to merge the Property first or do the query in the same transaction as you persist the Offer:
#Override
public void Add(Offer offer, int peropertyId) {
Property property = em.find(Property.class, propertyId);
offer.setPeropertyId(property);
em.persist(offer);
}
or
#Override
public void Add(Offer offer, Property peroperty) {
Property managedProperty = em.merge(property);
offer.setPeropertyId(managedProperty);
em.persist(offer);
}
I fixed it. If you look at the code for servlet, it was the problem with my if condition that checks the action parameter. It was meant to be if action is not empty but it checks if action is empty. I found this issue by creating an integer that increments itself when it reaches certain stages within the code.
I think you were right on the fact that I had to do the getting property id and buyer id on the same transaction. Otherwise that would have been the next issue for me. Thank you.
I have a rest server and client which uses this API. I have a list of hotels and it had passed well until I added bidirectional dependencies to other entities.After that I start receive an endless array of entities which just repeat the same row in database.
It is my first project with hibernate so may be I made trivial mistakes of novice.
Hotel:
#Entity
#Table(name = "hotels", schema = "", catalog = "mydb")
public class HotelsEntity implements HospitalityEntity{
private int idHotel;
private String name;
private String region;
private String description;
// private byte[] photo;
private HotelPropertyEntity property;
private List<RoomEntity> rooms;
#OneToOne(mappedBy = "hotel")
public HotelPropertyEntity getProperty() {
return property;
}
public void setProperty(HotelPropertyEntity property) {
this.property = property;
}
#OneToMany(mappedBy = "hotel")
public List<RoomEntity> getRooms() {
return rooms;
}
public void setRooms(List<RoomEntity> rooms) {
this.rooms = rooms;
}
#Id
#Column(name = "id_hotel", unique = true)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getIdHotel() {
return idHotel;
}
public void setIdHotel(int idHotel) {
this.idHotel = idHotel;
}
#Basic
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "region")
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
#Basic
#Column(name = "description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
HotelProperty
#Entity
#Table(name = "hotel_property", schema = "", catalog = "mydb")
public class HotelPropertyEntity {
private int idHotelProperty;
private byte hasPool;
private byte hasTennisCourt;
private byte hasWaterslides;
private HotelsEntity hotel;
#Id
#Column(name = "id_hotel_property", unique = true)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getIdHotelProperty() {
return idHotelProperty;
}
public void setIdHotelProperty(int idHotelProperty) {
this.idHotelProperty = idHotelProperty;
}
#Basic
#Column(name = "has_pool", columnDefinition = "BIT", length = 1)
public byte getHasPool() {
return hasPool;
}
public void setHasPool(byte hasPool) {
this.hasPool = hasPool;
}
#Basic
#Column(name = "has_tennis_court", columnDefinition = "BIT", length = 1)
public byte getHasTennisCourt() {
return hasTennisCourt;
}
public void setHasTennisCourt(byte hasTennisCourt) {
this.hasTennisCourt = hasTennisCourt;
}
#Basic
#Column(name = "has_waterslides", columnDefinition = "BIT", length = 1)
public byte getHasWaterslides() {
return hasWaterslides;
}
public void setHasWaterslides(byte hasWaterslides) {
this.hasWaterslides = hasWaterslides;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id_hotel_property")
public HotelsEntity getHotel() {
return hotel;
}
public void setHotel(HotelsEntity hotel) {
this.hotel = hotel;
}
Room:
#Entity
#Table(name = "room", schema = "", catalog = "mydb")
public class RoomEntity {
private int idRoom;
private String roomType;
private int peopleCapacity;
private Boolean booked;
private Boolean locked;
private HotelsEntity hotel;
private InventoriesEntity inventory;
private RoomPropertyEntity roomProperty;
#OneToOne(mappedBy = "room")
public RoomPropertyEntity getRoom() {
return roomProperty;
}
public void setRoom(RoomPropertyEntity roomProperty) {
this.roomProperty = roomProperty;
}
#OneToOne
#JoinColumn(name = "id_room")
public InventoriesEntity getInventory() {
return inventory;
}
public void setInventory(InventoriesEntity inventory) {
this.inventory = inventory;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_hotel")
public HotelsEntity getHotel() {
return hotel;
}
public void setHotel(HotelsEntity hotel) {
this.hotel = hotel;
}
#Id
#Column(name = "id_room")
public int getIdRoom() {
return idRoom;
}
public void setIdRoom(int idRoom) {
this.idRoom = idRoom;
}
#Basic
#Column(name = "room_type")
public String getRoomType() {
return roomType;
}
public void setRoomType(String roomType) {
this.roomType = roomType;
}
#Basic
#Column(name = "people_capacity")
public int getPeopleCapacity() {
return peopleCapacity;
}
public void setPeopleCapacity(int peopleCapacity) {
this.peopleCapacity = peopleCapacity;
}
#Basic
#Column(name = "booked", columnDefinition = "BIT", length = 1)
public Boolean getBooked() {
return booked;
}
public void setBooked(Boolean booked) {
this.booked = booked;
}
#Basic
#Column(name = "locked", columnDefinition = "BIT", length = 1)
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
Could you please advise what is a way or ways to tell hibernate to stop this cycle?
p.s
This code contains another one issue. I f I remove one to one dependency and remain only one to many I receive failed to lazily initialize a collection of role: com.example.model.HotelsEntity.rooms, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.example.model.HotelsEntity["rooms"])
You need to mark entity as not serializable for JSON. Please use #JsonIgnore or #JsonIgnoreProperties("field") on one of the sides of the relations (the annotation is class-level).
I use Hibernate and
have two entities(City and Region) with OneToMany relation.
the First:
#Entity
#Table(name = "p_region")
public class Region implements Serializable{
#OneToMany(mappedBy = "region",fetch= FetchType.LAZY, cascade = CascadeType.MERGE)
private List<City> citys;
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
//++++++++++++++++++++ GETSET
public List<City> getCitys() {
return citys;
}
public void setCitys(List<City> citys) {
this.citys = citys;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and the second one:
#Entity
#Table(name = "p_city")
public class City implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotEmpty(message = "Название не должно быть пустым")
#Length(max = 10, min = 2, message = "Название должно быть менее 2 символов и не
более 100")
private String cityName;
#NotEmpty(message = "Код города не должно быть пустым")
private String cityCode;
#Column(name = "zone")
private Integer zone;
#Basic(optional = true)
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date entryDate = Calendar.getInstance().getTime();
#ManyToOne()
private Region region;
#Basic(optional = true)
private String zip_code;
// GET SET ::::::::::::::::::::::::::::::::::
public Integer getZone() {
return zone;
}
public void setZone(Integer zone) {
this.zone = zone;
}
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
public void delete() {
System.out.println("QQQQQQQQQQQQQQQQQQQQQQ");
}
public String getCityCode() {
return cityCode;
}
public void setCityCode(String cityCode) {
this.cityCode = cityCode;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public Date getEntryDate() {
return entryDate;
}
public void setEntryDate(Date entryDate) {
this.entryDate = entryDate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getZip_code() {
return zip_code;
}
public void setZip_code(String zip_code) {
this.zip_code = zip_code;
}
}
When I try to get simple Object(City) with JSON it returns the cycle:
{"id":577,"region":{"name":"нет региона","id":15,"citys":[{"id":577,"region":
{"name":"нет региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет......so on.
Are there any solutions for this issue?
You need to break the bi-directional relationship between your entity before converting to JSON.
I think there are two options:
Iterate the child collection, e.g. citys in Region and set Region to null. This way, circular dependency would be broken. You my want to add one name mapped attribute regionId in the City so that relational info is still available.
Create another set of POJO objects without circular dependency, copy the values from Entity Objects and then get the JSON using POJO objects.