How to create a boolean column in MySQL table? - mysql

I want to create a table in MySQL database that have a boolean column with values 'active' and 'inactive'. How can i do that?
My Entity class:
#Entity
#Table(name = "organization")
public class OrganizationEntity {
private Long id;
private String nameEntity;
private String provinceEntity;
private String supporterEntity;
private String supporterAddressEntity;
private boolean active;
#Id
#GeneratedValue
#Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "name")
public String getNameEntity() {
return nameEntity;
}
public void setNameEntity(String nameEntity) {
this.nameEntity = nameEntity;
}
#Column(name = "province")
public String getProvinceEntity() {
return provinceEntity;
}
public void setProvinceEntity(String provinceEntity) {
this.provinceEntity = provinceEntity;
}
#Column(name = "supporter_name")
public String getSupporterEntity() {
return supporterEntity;
}
public void setSupporterEntity(String supporterEntity) {
this.supporterEntity = supporterEntity;
}
#Column(name = "supporter_address")
public String getSupporterAddressEntity() {
return supporterAddressEntity;
}
public void setSupporterAddressEntity(String supporterAddressEntity) {
this.supporterAddressEntity = supporterAddressEntity;
}
#Column(name = "active")
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
My organization entity class have a boolean 'active' field that shows an organization is active or inactive. Now how can I have a column in database table for that?

Technically MySQL does not have a boolean type. BOOL and BOOLEAN converts to TINYINT(1).
From the MySQL documentation:
A value of zero is considered false. Nonzero values are considered true
You should be able to use the TINYINT(1) column from your code as some languages handle 1 as true and 0 as false (unless overwritten by you).
Not sure what language you are using (C# ?) you can try the following:
#Column(name = "active")
public boolean isActive() {
return Convert.ToBoolean(active);
}
This is untested, so give it a go.

You can simply use boolean primitive type (but be sure you have NOT NULL column) or Boolean wrapper for nullable column. JPA providers (Hibernate or EclipseLink) are smart enough to convert that behind the scenes.
Use for field access type:
#Basic(optional = false)
#Column(name = "active")
private boolean active;
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
or even for property access type:
private boolean active;
#Basic(optional = false)
#Column(name = "active")
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}

Related

Why JPA Hibernate changes the name of the field?

In model class I have isActive field with is boolean, that represent the is_active field in MySql DB. Here is whole model class:
package ca.gatin.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "Account")
public class Account {
#Id
#GeneratedValue
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(nullable = false, unique = true)
private String email;
#Column(nullable = false)
private String password;
#Column(name = "is_active", nullable = false)
private boolean isActive;
#Column(name = "date_created")
private Date dateCreated;
#Column(name = "date_last_modified")
private Date dateLastModified;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Date getDateLastModified() {
return dateLastModified;
}
public void setDateLastModified(Date dateLastModified) {
this.dateLastModified = dateLastModified;
}
}
But when I fetch account let's say through REST API like:
#RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ServiceResponse<Account> getAll(#PathVariable("id") Long id) {
ServiceResponse<Account> serviceResponse = accountService.getAccountById(id);
return serviceResponse;
}
In a reply object I get isActive field renamed by Hibernate to "active" like this:
{
"id": 19,
"firstName": "Julia",
"lastName": "Sarandi",
"email": "julia#gatin.ca",
"password": "111111",
"dateCreated": 1451293826000,
"dateLastModified": null,
"active": true
}
Why? Why all other field's names stay same as in Account class, but isActive is renamed?
That is one question, and another question is:
I am new in Hibernate, and I do no understand why in logs of Hibernate DB requests is shows some weird queries:
Hibernate: select account0_.id as id1_0_0_, account0_.date_created as date_cre2_0_0_, account0_.date_last_modified as date_las3_0_0_, account0_.email as email4_0_0_, account0_.first_name as first_na5_0_0_, account0_.is_active as is_activ6_0_0_, account0_.last_name as last_nam7_0_0_, account0_.password as password8_0_0_ from Account account0_ where account0_.id=?
What query language is it? What are symbols: "0_", "0_0_". Can I switch logs to show MySQL queries to make it more understandable?
FYI
In my application.properties file I have following configuration:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy
Change getter and setter method name for isActive field as:
public boolean getIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
Then it return isActive in response.
That has nothing to do with Hibernate, and everything to do with your JSON marshaller. Spring uses Jackson, and Jackson uses bean properties (i.e. getters) to access the data and transform them to JSON fields. Your getter is named isActive(), and thus corresponds to a bean property named active, hence the name of the attribute in the JSON.
If you want the JSON field to be named isActive, then your getter should be isIsActive(). Or much better, you should annotate it with #JsonProperty("isActive").
To answer your second question, the query is a SQL query, generated by Hibernate. It changes the name of tables and assigns aliases to columns mainly to disambiguate tables, and fields of different tables that could have the same name, AFAIK.

Control the order the tables have been created in jpa

Does it exist a way to control the order in which the tables have been created by the persistence provider? I got this mysql 1146 error. I suppose it happens because it try to create an entity that needs for reservation table but it doesn't found it so this cause the following exception. Does exist a way to fix that?
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'volaconnoi_db.reservation' doesn't exist
Error Code: 1146
Call: ALTER TABLE RESERVATION ADD CONSTRAINT FK_RESERVATION_ROUTE_ID_ROUTE FOREIGN KEY (ROUTE_ID_ROUTE) REFERENCES ROUTE (ID_ROUTE)
Query: DataModifyQuery(sql="ALTER TABLE RESERVATION ADD CONSTRAINT FK_RESERVATION_ROUTE_ID_ROUTE FOREIGN KEY (ROUTE_ID_ROUTE) REFERENCES ROUTE (ID_ROUTE)")
This is the USER_CREDENTIAL entity
#Entity
#Table(name = "USER_CREDENTIAL")
#SecondaryTable(name = "CLIENT", pkJoinColumns=#PrimaryKeyJoinColumn(name="USERNAME"))
public class UserCredential implements Serializable
{
private String username;
private String password;
private String email;
private String group_name;
private Date create_date;
private String name;
private String surname;
private String address;
private String city;
private String zip_code;
private String country;
private int fidelity_points;
private List<PhoneNumber> phoneNumbers;
private List<Reservation> reservationsList;
public UserCredential()
{
}
#Id
#Column(name = "USERNAME", nullable = false)
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
#Column(name = "PASSWORD", nullable = false)
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
#Column(name = "EMAIL", nullable = false)
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
#Column(name = "GROUP_NAME", insertable = false, updatable = false)
public String getGroup_name()
{
return group_name;
}
public void setGroup_name(String group_name)
{
this.group_name = group_name;
}
#Column(name = "CREATE_DATE", insertable = false, updatable = false)
#Temporal(TemporalType.TIMESTAMP)
public Date getCreate_date()
{
return create_date;
}
public void setCreate_date(Date create_date)
{
this.create_date = create_date;
}
#Column(name = "NAME", nullable= false, table="CLIENT")
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
#Column(name = "SURNAME", nullable= false, table = "CLIENT")
public String getSurname()
{
return surname;
}
public void setSurname(String surname)
{
this.surname = surname;
}
#Column(name = "ADDRESS", nullable= false , table = "CLIENT")
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
#Column(name = "CITY", nullable = false, table = "CLIENT")
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
#Column(name = "ZIP_CODE", nullable = false, table = "CLIENT")
public String getZip_code()
{
return zip_code;
}
public void setZip_code(String zip_code)
{
this.zip_code = zip_code;
}
#Column(name = "COUNTRY", nullable = false, table = "CLIENT")
public String getCountry()
{
return country;
}
public void setCountry(String country)
{
this.country = country;
}
#Column(name = "FIDELITY_POINTS", nullable = false, table = "CLIENT")
public int getFidelity_points()
{
return fidelity_points;
}
public void setFidelity_points(int fidelity_points)
{
this.fidelity_points = fidelity_points;
}
#ElementCollection
#CollectionTable(name = "CLIENT_PHONE_NUMBER", joinColumns = #JoinColumn(name = "USERNAME"))
public List<PhoneNumber> getPhoneNumbers()
{
return phoneNumbers;
}
public void setPhoneNumbers (List<PhoneNumber> phoneNumbers)
{
this.phoneNumbers = phoneNumbers;
}
#OneToMany(mappedBy = "username", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public List<Reservation> getReservationsList()
{
return reservationsList;
}
public void setReservationsList(List<Reservation> reservationsList)
{
this.reservationsList = reservationsList;
}
#Override
public int hashCode()
{
int hash = 0;
hash += (username != null ? username.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object)
{
// TODO: Warning - this method won't work in the case the username fields are not set
if (!(object instanceof UserCredential))
{
return false;
}
UserCredential other = (UserCredential) object;
if ((this.username == null && other.username != null) || (this.username != null && !this.username.equals(other.username)))
{
return false;
}
return true;
}
#Override
public String toString()
{
return "it.volaconoi.entity.UserCredential[ id=" + username + " ]";
}
}
THIS IS THE ROUTE ENTITY
#Entity
#Table(name = "ROUTE")
public class Route implements Serializable
{
private String id_route;
private String airlane;
private String aircraft_id;
private Airport airport_city_source;
private Airport airport_city_dest;
private Date departure_date;
private Date arrival_date;
private String travel_class;
private int seats;
private float price;
private List<Reservation> reservationsList;
public Route()
{
}
#PrePersist
public void setIdRoute()
{
SimpleDateFormat sdf = new SimpleDateFormat("ddMMYYYYHHmm");
String format_departure_date = sdf.format(this.getDeparture_date());
String unique_id_route = this.getAirlane() +
this.getAircraft_id() +
this.getAirport_city_source().getCity() +
this.getAirport_city_dest().getCity() +
format_departure_date;
this.setId_route(unique_id_route.replaceAll(" ", ""));
}
#Id
#Column(name = "ID_ROUTE")
public String getId_route()
{
return id_route;
}
public void setId_route(String id_route)
{
this.id_route = id_route;
}
#Column(name = "AIRLANE", nullable = false)
public String getAirlane()
{
return airlane;
}
public void setAirlane(String airlane)
{
this.airlane = airlane;
}
#Column(name = "AIRCRAFT_ID", nullable = false)
public String getAircraft_id()
{
return aircraft_id;
}
public void setAircraft_id(String aircraft_id)
{
this.aircraft_id = aircraft_id;
}
#OneToOne(optional = false)
public Airport getAirport_city_source()
{
return airport_city_source;
}
public void setAirport_city_source(Airport airport_city_source)
{
this.airport_city_source = airport_city_source;
}
#OneToOne(optional = false)
public Airport getAirport_city_dest()
{
return airport_city_dest;
}
public void setAirport_city_dest(Airport airport_city_dest)
{
this.airport_city_dest = airport_city_dest;
}
#Column(name = "DEPARTURE_DATE", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
public Date getDeparture_date()
{
return this.departure_date;
}
public void setDeparture_date(Date departure_date)
{
this.departure_date = departure_date;
}
#Column(name = "ARRIVAL_DATE", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
public Date getArrival_date()
{
return arrival_date;
}
public void setArrival_date(Date arrival_date)
{
this.arrival_date = arrival_date;
}
#Column(name = "TRAVEL_CLASS", nullable = false)
public String getTravel_class()
{
return travel_class;
}
public void setTravel_class(String travel_class)
{
this.travel_class = travel_class;
}
#Column(name = "SEATS", nullable = false)
public int getSeats()
{
return seats;
}
public void setSeats(int seats)
{
this.seats = seats;
}
#Column(name = "PRICE", nullable = false)
public float getPrice()
{
return price;
}
public void setPrice(float price)
{
this.price = price;
}
#OneToMany(mappedBy = "route", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public List<Reservation> getReservationsList()
{
return reservationsList;
}
public void setReservationsList(List<Reservation> reservationsList)
{
this.reservationsList = reservationsList;
}
#Override
public int hashCode()
{
int hash = 0;
hash += (id_route != null ? id_route.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object)
{
// TODO: Warning - this method won't work in the case the id_route fields are not set
if (!(object instanceof Route))
{
return false;
}
Route other = (Route) object;
if ((this.id_route == null && other.id_route != null) || (this.id_route != null && !this.id_route.equals(other.id_route)))
{
return false;
}
return true;
}
#Override
public String toString()
{
return "it.volaconoi.entity.Route[ id=" + id_route + " ]";
}
}
This is the RESERVATION entity
#Entity
#Table(name = "RESERVATION")
public class Reservation implements Serializable
{
private String id;
private int passengers;
private int luggages;
private float price;
private Date date_reservation;
private boolean cancelled;
private UserCredential username;
private Route route;
public Reservation()
{
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_RESERVATION")
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
#Column(name = "PASSENGERS", nullable = false)
public int getPassengers()
{
return passengers;
}
public void setPassengers(int passengers)
{
this.passengers = passengers;
}
#Column(name = "LUGGAGES", nullable = false)
public int getLuggages()
{
return luggages;
}
public void setLuggages(int luggages)
{
this.luggages = luggages;
}
#Column(name = "PRICE", nullable = false)
public float getPrice()
{
return price;
}
public void setPrice(float price)
{
this.price = price;
}
#Column(name = "DATE_PLACED", insertable = false, updatable = false)
#Temporal(TemporalType.TIMESTAMP)
public Date getDate_reservation()
{
return date_reservation;
}
public void setDate_reservation(Date date_reservation)
{
this.date_reservation = date_reservation;
}
#Column(name = "CANCELLED", nullable = false)
public boolean isCancelled()
{
return cancelled;
}
public void setCancelled(boolean cancelled)
{
this.cancelled = cancelled;
}
#ManyToOne
#JoinColumn(name = "USERNAME", nullable = false)
public UserCredential getUsername()
{
return username;
}
public void setUsername(UserCredential username)
{
this.username = username;
}
#ManyToOne
#JoinColumn(name = "ID_ROUTE", nullable = false)
public Route getRoute()
{
return route;
}
public void setRoute(Route route)
{
this.route = route;
}
#Override
public int hashCode()
{
int hash = 0;
hash += (id != null ? id.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 Reservation))
{
return false;
}
Reservation other = (Reservation) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id)))
{
return false;
}
return true;
}
#Override
public String toString()
{
return "it.volaconoi.entity.Reservation[ id=" + id + " ]";
}
}
As you may see these three entities are related to each one
I believe this is an error so fixing this may make your problem go away. Then again this may be unrelated:
In Reservation, the type of id is String, but in getId() you specify GenerationType.IDENTITY. AFAIK MySQL doesn't support auto generation of string IDs but only integer IDs. Remove this and see if things work.
UPDATE:
I've reproduced the error on my machine, and this is indeed the problem. If you check your output you will find a warning (not an error) similar to:
[EL Warning]: 2014-06-20
15:47:46.224--ServerSession(1565614310)--Exception [EclipseLink-4002]
(Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5):
org.eclipse.persistence.exceptions.DatabaseException Internal
Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
Incorrect column specifier for column 'ID' Error Code: 1063 Call:
CREATE TABLE NEWENTITY (ID VARCHAR(255) AUTO_INCREMENT NOT NULL, NAME
VARCHAR(255), PRIMARY KEY (ID)) Query: DataModifyQuery(sql="CREATE
TABLE NEWENTITY (ID VARCHAR(255) AUTO_INCREMENT NOT NULL, NAME
VARCHAR(255), PRIMARY KEY (ID))")
I imagine you missed it because it's a warning and not an error. I also imagine this gets output as a warning and not an error because sometimes an error creating the table is not an issue (for example, if the table already exists). EclipseLink apparently isn't smart enough to handle cases where there is a true error, so it outputs as a warning (see "JPA sucks", above).
The EclipseLink/MySQL combination does not support a generation type of IDENTITY for String IDs. IDENTITY means that it's up to the database (and not the JPA implementation provider) to create the ID. MySQL only supports creating integer IDs so the column type must be integer if you use AUTO INCREMENT (see the generated code).
If you really want your IDs to be a String but also automatically generate an ID, then use a generation type of AUTO. AUTO means the JPA implementation provider will handle creating the IDs; EclipseLink will use a sequence table and will handle converting the values there to a String for you.

Excluding properties from JSON processing in Struts2

I have the following (full) entity class.
public class StateTable implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "state_id", nullable = false)
private Long stateId;
#Column(name = "state_name", length = 45)
private String stateName;
#OneToMany(mappedBy = "stateId", fetch = FetchType.LAZY)
private Set<UserTable> userTableSet;
#OneToMany(mappedBy = "stateId", fetch = FetchType.LAZY)
private Set<City> citySet;
#OneToMany(mappedBy = "stateId", fetch = FetchType.LAZY)
private Set<Inquiry> inquirySet;
#OneToMany(mappedBy = "shippingState", fetch = FetchType.LAZY)
private Set<OrderTable> orderTableSet;
#OneToMany(mappedBy = "paymentState", fetch = FetchType.LAZY)
private Set<OrderTable> orderTableSet1;
#JoinColumn(name = "country_id", referencedColumnName = "country_id")
#ManyToOne(fetch = FetchType.LAZY)
private Country countryId;
public StateTable() {
}
public StateTable(Long stateId) {
this.stateId = stateId;
}
public Long getStateId() {
return stateId;
}
public void setStateId(Long stateId) {
this.stateId = stateId;
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
#XmlTransient
public Set<UserTable> getUserTableSet() {
return userTableSet;
}
public void setUserTableSet(Set<UserTable> userTableSet) {
this.userTableSet = userTableSet;
}
#XmlTransient
public Set<City> getCitySet() {
return citySet;
}
public void setCitySet(Set<City> citySet) {
this.citySet = citySet;
}
#XmlTransient
public Set<Inquiry> getInquirySet() {
return inquirySet;
}
public void setInquirySet(Set<Inquiry> inquirySet) {
this.inquirySet = inquirySet;
}
#XmlTransient
public Set<OrderTable> getOrderTableSet() {
return orderTableSet;
}
public void setOrderTableSet(Set<OrderTable> orderTableSet) {
this.orderTableSet = orderTableSet;
}
#XmlTransient
public Set<OrderTable> getOrderTableSet1() {
return orderTableSet1;
}
public void setOrderTableSet1(Set<OrderTable> orderTableSet1) {
this.orderTableSet1 = orderTableSet1;
}
public Country getCountryId() {
return countryId;
}
public void setCountryId(Country countryId) {
this.countryId = countryId;
}
#Override
public int hashCode() {
int hash = 0;
hash += (stateId != null ? stateId.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 StateTable)) {
return false;
}
StateTable other = (StateTable) object;
if ((this.stateId == null && other.stateId != null) || (this.stateId != null && !this.stateId.equals(other.stateId))) {
return false;
}
return true;
}
#Override
public String toString() {
return "model.StateTable[ stateId=" + stateId + " ]";
}
}
I need only two properties from this class as a JSON response namely, stateId and stateName. The rest of the properties must be ignored from being processed/serialized by JSON.
I have tried to set json.excludeProperties to the json interceptor as follows.
#Namespace("/admin_side")
#ResultPath("/WEB-INF/content")
#ParentPackage(value="json-default")
public final class StateListAction extends ActionSupport implements Serializable, ValidationAware
{
#Autowired
private final transient SharableService sharableService=null;
private static final long serialVersionUID = 1L;
private Long id;
List<StateTable>stateTables=new ArrayList<StateTable>();
public StateListAction() {}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JSON(name="stateTables")
public List<StateTable> getStateTables() {
return stateTables;
}
public void setStateTables(List<StateTable> stateTables) {
this.stateTables = stateTables;
}
#Action(value = "PopulateStateList",
results = {
#Result(type="json", name=ActionSupport.SUCCESS, params={"json.enableSMD", "true", "json.enableGZIP", "true", "json.excludeNullProperties", "true", "json.root", "stateTables", "json.excludeProperties", "userTableSet, citySet, inquirySet, orderTableSet, orderTableSet1, countryId", "validation.validateAnnotatedMethodOnly", "true"})})
public String populateStateList() throws Exception
{
System.out.println("countryId = "+id);
stateTables=sharableService.findStatesByCountryId(id);
return ActionSupport.SUCCESS;
}
}
The remaining properties are expected to be ignored after doing this but it doesn't seem to work. Number of SQL statements associated with all of the entity classes are generated which in turn causes other severe errors to occur like,
org.apache.struts2.json.JSONException: java.lang.IllegalAccessException: Class
org.apache.struts2.json.JSONWriter can not access a member of class
org.joda.time.tz.DateTimeZoneBuilder$PrecalculatedZone with modifiers "public"
What am I missing here? How to ignore all the properties except stateId and stateName?
I'm using Struts2-json-plugin-2.3.16.
You need to configure includeProperties in the json result. For example
#Result(type="json", params = {"contentType", "text/javascript", "includeProperties",
"stateTables\\[\\d+\\]\\.stateId,stateTables\\[\\d+\\]\\.stateName"})

Adding data to multiple tables using Spring forms in Spring MVC

I have the following database schema and I need to add data to all three tables using a single view http://i.stack.imgur.com/3HXhC.png (Due to stackoverflow rules, I cannot link the image directly).
What I hope to achieve, is to create an order, have it given an Workshop order id, and have it linked to LineItems which will let the user specify the quantity of items from the Inventory table to be added to the order.
I can create a workshop order in my database, and create a lineitem with the workshop orders id, and add the id and quantity from an inventory item into the lineitem table, and then use the attached code to display each lineitem orderline, with the total amount of items, which item is in the order, total price, customer name etc.
How do I go about creating a view that will let me create an order this way? The flow I imagine is:
Create workshop order -> add line items from inventory -> save the order.
Having worked on Spring and Hibernate for only a couple of weeks, I have not really figured out a smart approach to solve this, but hopefully someone in here has. By all means, feel free to criticize my database scheme, my classes and anything else. It may be a stupid design, not well suited for an actual production system.
I have attached my primary classes involved in this.
LineItems.java
#Entity
#Table(name = "LINE_ITEMS")
#AssociationOverrides({
#AssociationOverride(name = "pk.inventory",
joinColumns = #JoinColumn(name = "INVENTORY_Id")),
#AssociationOverride(name = "pk.workshop",
joinColumns = #JoinColumn(name = "WORKSHOP_ORDERS_Id"))
})
public class LineItems implements Serializable {
private static final long serialVersionUID = 5703588914404465647L;
#EmbeddedId
private LineItemsPK pk = new LineItemsPK();
private int quantity;
public LineItems() {
}
public LineItemsPK getPK() {
return pk;
}
public void setPK(LineItemsPK pk) {
this.pk = pk;
}
#Column(name = "WORKSHOP_ORDERS_Id", nullable=false, updatable=false,
insertable=false)
public Long getWorkshopOrdersId() {
return getPK().getWorkshop().getId();
}
#Column(name = "Id")
#JoinColumn(name="INVENTORY_Id", nullable=false, updatable=false, insertable=false)
public Long getInventoryId() {
return getPK().getInventory().getId();
}
#ManyToOne
public Workshop getWorkshop() {
return getPK().getWorkshop();
}
public void setWorkshop(Workshop workshop) {
getPK().setWorkshop(workshop);
}
#ManyToOne
#JoinColumn(name = "INVENTORY_Id")
public Inventory getInventory() {
return getPK().getInventory();
}
public void setInventory(Inventory inventory) {
getPK().setInventory(inventory);
}
public int getQuantity() {
return this.quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LineItems that = (LineItems) o;
if (getPK() != null ? !getPK().equals(that.getPK())
: that.getPK() != null) {
return false;
}
return true;
}
public int hashCode() {
return (getPK() != null ? getPK().hashCode() : 0);
}
}
LineItemsPK.java
#Embeddable
public class LineItemsPK implements Serializable {
private static final long serialVersionUID = -4285130025882317338L;
#ManyToOne
private Inventory inventory;
#ManyToOne
private Workshop workshop;
public Workshop getWorkshop() {
return workshop;
}
public void setWorkshop(Workshop workshop) {
this.workshop = workshop;
}
public Inventory getInventory() {
return inventory;
}
public void setInventory(Inventory inventory) {
this.inventory = inventory;
}
#Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
}
LineItemsPK that = (LineItemsPK) o;
if(workshop != null ? !workshop.equals(that.workshop) : that.workshop != null) {
return false;
}
if(inventory != null ? !inventory.equals(that.inventory) : that.inventory != null) {
return false;
}
return true;
}
#Override
public int hashCode() {
int result;
result = (workshop != null ? workshop.hashCode() : 0);
result = 31 * result + (inventory != null ? inventory.hashCode() : 0);
return result;
}
}
Workshop.java
#Entity
#Table(name = "WORKSHOP_ORDERS")
public class Workshop implements Serializable {
private static final long serialVersionUID = -8106245965993313684L;
public Long id;
public Long inventoryItemId;
public String workshopService;
public String workshopNotes;
public Long customersId;
public Long paymentId;
private Customer customer;
private Payment payment;
private Set<LineItems> lineItems = new HashSet<LineItems>(0);
public Workshop() {
}
public Workshop(Long inventoryItemId, String workshopService, String workshopNotes,
Customer customer, Payment payment) {
this.inventoryItemId = inventoryItemId;
this.workshopService = workshopService;
this.workshopNotes = workshopNotes;
this.customer = customer;
this.payment = payment;
}
public Workshop(Long inventoryItemId, String workshopService, String workshopNotes,
Customer customer, Payment payment, Set<LineItems> lineItems) {
this.inventoryItemId = inventoryItemId;
this.workshopService = workshopService;
this.workshopNotes = workshopNotes;
this.customer = customer;
this.payment = payment;
this.lineItems = lineItems;
}
#OneToMany(mappedBy = "pk.workshop", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Set<LineItems> getLineItems() {
return this.lineItems;
}
public void setLineItems(Set<LineItems> lineItems) {
this.lineItems = lineItems;
}
#ManyToOne
#JoinColumn(name="CUSTOMERS_Id", nullable = false, insertable = false, updatable = false)
public Customer getCustomer() {
return customer;
}
public void setCustomer(final Customer customer) {
this.customer = customer;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="PAYMENT_Id", insertable = false, updatable = false, nullable = false)
public Payment getPayment() {
return payment;
}
public void setPayment(final Payment payment) {
this.payment = payment;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "Id", nullable = false)
public Long getId() {
return id;
}
#Column(name = "InventoryItemId")
public Long getInventoryItemId() {
return inventoryItemId;
}
#Column(name = "WorkshopService")
public String getWorkshopService() {
return workshopService;
}
#Column(name = "WorkshopNotes")
public String getWorkshopNotes() {
return workshopNotes;
}
#Column(name = "CUSTOMERS_Id")
public Long getCustomersId() {
return customersId;
}
#Column(name = "PAYMENT_Id")
public Long getPaymentId() {
return paymentId;
}
public void setId(Long id) {
this.id = id;
}
public void setInventoryItemId(Long inventoryItemId) {
this.inventoryItemId = inventoryItemId;
}
public void setWorkshopService(String workshopService) {
this.workshopService = workshopService;
}
public void setWorkshopNotes(String workshopNotes) {
this.workshopNotes = workshopNotes;
}
public void setCustomersId(Long customersId) {
this.customersId = customersId;
}
public void setPaymentId(Long paymentId) {
this.paymentId = paymentId;
}
public String toString() {
return "Customer id: " + this.customersId + "Notes: " + workshopNotes;
}
}
Inventory.java
#Entity
#Table(name = "INVENTORY")
public class Inventory implements Serializable {
private static final long serialVersionUID = -8907719450013387551L;
private Long id;
private String itemName;
private String itemVendorName;
private Long itemInventoryStatus;
private Double itemBuyPrice;
private Double itemSellPrice;
private Set<LineItems> lineItems = new HashSet<LineItems>(0);
public Inventory() {
}
public Inventory(String itemName, String itemVendorName, Long itemInventoryStatus,
Double itemBuyPrice, Double itemSellPrice) {
this.itemName = itemName;
this.itemVendorName = itemVendorName;
this.itemInventoryStatus = itemInventoryStatus;
this.itemBuyPrice = itemBuyPrice;
this.itemSellPrice = itemSellPrice;
}
public Inventory(String itemName, String itemVendorName, Long itemInventoryStatus,
Double itemBuyPrice, Double itemSellPrice, Set<LineItems> lineItems) {
this.itemName = itemName;
this.itemVendorName = itemVendorName;
this.itemInventoryStatus = itemInventoryStatus;
this.itemBuyPrice = itemBuyPrice;
this.itemSellPrice = itemSellPrice;
this.lineItems = lineItems;
}
#OneToMany(mappedBy = "pk.inventory", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Set<LineItems> getLineItems() {
return this.lineItems;
}
public void setLineItems(Set<LineItems> lineItems) {
this.lineItems = lineItems;
}
#Id
#Column(name = "Id", nullable = false)
#GeneratedValue(strategy = IDENTITY)
public Long getId() {
return this.id;
}
#Column(name = "ItemName")
public String getItemName() {
return this.itemName;
}
#Column(name = "ItemVendorName")
public String getItemVendorName() {
return this.itemVendorName;
}
#Column(name = "ItemInventoryStatus")
public Long getItemInventoryStatus() {
return this.itemInventoryStatus;
}
#Column(name = "ItemBuyPrice")
public Double getItemBuyPrice() {
return this.itemBuyPrice;
}
#Column(name = "ItemSellPrice")
public Double getItemSellPrice() {
return this.itemSellPrice;
}
public void setId(Long id) {
this.id = id;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public void setItemVendorName(String itemVendorName) {
this.itemVendorName = itemVendorName;
}
public void setItemInventoryStatus(Long itemInventoryStatus) {
this.itemInventoryStatus = itemInventoryStatus;
}
public void setItemBuyPrice(Double itemBuyPrice) {
this.itemBuyPrice = itemBuyPrice;
}
public void setItemSellPrice(Double itemSellPrice) {
this.itemSellPrice = itemSellPrice;
}
public String toString() {
return "Item id:" + this.id + " ItemName: " + this.itemName +
" ItemInventoryStatus: " + this.itemInventoryStatus +
" ItemBuyPrice: " + this.itemBuyPrice + " ItemSellPrice " + this.itemSellPrice;
}
}
This isn't really a question as it is more of a "how would I do this"
What have you tried already?
Where are you running into trouble?
etc.
Your view logic should not be coupled with your domain layer, what I mean is, you write your forms to be as usable as possible yet, still get the information you need. Once you post the information to the backing Controller, you do the required business logic in order to line up how the entities persist, etc.
Continuing this line of thinking, your controller should only be worried about web layer exceptions, and passing information on to the Business / Service Layer. From the Business / Service layer you execute required logic, and pass on to the Domain / Repository layer. This gives a clear separation of concerns allowing for easier testing.

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.