I have an application (Spring 4 MVC+Hibernate 4+MySQL+Maven integration example using annotations) , integrating Spring with Hibernate using annotation based configuration.
I have this domain object:
#Entity
#Table(name="t_device")
public class Device {
enum Type {
IOS,
ANDROID
}
public Device() {
super();
}
public Device(String key) {
super();
this.key = key;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty
#Size(min=1, max=50)
#Column(name = "device_key", unique=true, nullable = false)
private String key;
#Column(name = "device_desc")
private String desc;
#Enumerated(EnumType.STRING)
#Column(name = "device_type")
private Type type;
#OneToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "application_id",
referencedColumnName = "id")
private Application application;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Application getApplication() {
return application;
}
public void setApplication(Application application) {
this.application = application;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((desc == null) ? 0 : desc.hashCode());
result = prime * result + id;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Device other = (Device) obj;
if (desc == null) {
if (other.desc != null)
return false;
} else if (!desc.equals(other.desc))
return false;
if (id != other.id)
return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
#Override
public String toString() {
return "Device [id=" + id + ", key=" + key + ", desc=" + desc + "]";
}
}
That is linked to this other one:
#Entity
#Table(name="t_device_event")
public class DeviceEvent {
public class Coordinates {
#Column(name = "device_lat")
private Double lat;
#Column(name = "device_lng")
private Double lng;
public Coordinates(Double lat, Double lng) {
super();
this.lat = lat;
this.lng = lng;
}
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
public Double getLng() {
return lng;
}
public void setLng(Double lng) {
this.lng = lng;
}
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne
private Device device;
private Long received;
private String message;
#Transient
private Coordinates coordinates;
public Coordinates getCoordinates() {
return coordinates;
}
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
public Long getReceived() {
return received;
}
public void setReceived(Long received) {
this.received = received;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public DeviceEvent(Device device) {
super();
this.device = device;
}
}
and this piece of code in the controller:
Device device = deviceService.findByKey("AS3989E506");
DeviceEvent deviceEvent = new DeviceEvent(device);
deviceEvent.setCoordinates(deviceEvent.new Coordinates(Double.MIN_VALUE, Double.MAX_VALUE));
deviceEvent.setMessage("message");
deviceEvent.setReceived(new Date().getTime());
deviceEventService.save(deviceEvent);
and the hibernate console:
Hibernate:
select
this_.id as id1_1_1_,
this_.application_id as applicat5_1_1_,
this_.device_desc as device_d2_1_1_,
this_.device_key as device_k3_1_1_,
this_.device_type as device_t4_1_1_,
applicatio2_.id as id1_0_0_,
applicatio2_.application_desc as applicat2_0_0_,
applicatio2_.application_key as applicat3_0_0_
from
t_device this_
left outer join
t_application applicatio2_
on this_.application_id=applicatio2_.id
where
this_.device_key=?
Hibernate:
insert
into
t_device_event
(device_id, message, received)
values
(?, ?, ?)
Hibernate:
select
this_.id as id1_1_1_,
this_.application_id as applicat5_1_1_,
this_.device_desc as device_d2_1_1_,
this_.device_key as device_k3_1_1_,
this_.device_type as device_t4_1_1_,
applicatio2_.id as id1_0_0_,
applicatio2_.application_desc as applicat2_0_0_,
applicatio2_.application_key as applicat3_0_0_
from
t_device this_
left outer join
t_application applicatio2_
on this_.application_id=applicatio2_.id
Here the services:
#Service("deviceEventService")
#Transactional
public class DeviceEventServiceImpl implements DeviceEventService {
#Autowired
private DeviceEventDao dao;
public void save(DeviceEvent deviceEvent) {
dao.save(deviceEvent);
}
}
the other:
#Service("deviceService")
#Transactional
public class DeviceServiceImpl implements DeviceService {
#Autowired
private DeviceDao dao;
public Device findById(int id) {
return dao.findById(id);
}
public void save(Device device) {
dao.save(device);
}
public void update(Device device) {
// TODO Auto-generated method stub
}
public void delete(Device device) {
// TODO Auto-generated method stub
}
public List<Device> findAll() {
return dao.findAll();
}
public Device findByKey(String key) {
return dao.findByKey(key);
}
public boolean isDeviceKeyUnique(Integer id, String key) {
Device device = findByKey(key);
return ( device == null || ((id != null) && (device.getId() == id)));
}
public void deleteByKey(String key) {
dao.deleteByKey (key);
}
}
But the field device_id of the table t_device_event is null !
May be #JoinColumn annotation will help you
#ManyToOne
#JoinColumn(name="device_id")
private Device device;
Related
I'm doing a simple exercise to learn JPA.
When I try to delete an entity of type User, which has a Collection of the other entity Score (annotated with #OneToMany) I get this error:
java.sql.SQLIntegrityConstraintViolationException: Column 'user' cannot be null
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 20 more
These are my classes:
User.java
#Entity
#Table(name = "user")
public class User
{
#Id
private Integer id;
#NotNull
#Size(max = 20)
private String name;
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true)
#JoinColumn(name = "user")
private Collection<Score> scores;
public User() {
}
public User(Integer id, String name, Collection<Score> scores) {
this.id = id;
this.name = name;
this.scores = scores;
}
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;
}
public Collection<Score> getScores() {
return scores;
}
public void setScores(Collection<Score> scores) {
this.scores = scores;
}
}
Score.java
#Entity
#Table(name = "score")
public class Score
{
#EmbeddedId
private ScoreId id;
#NotNull
private Integer points;
public Score() {
}
public Score(ScoreId id, Integer points) {
this.id = id;
this.points = points;
}
public ScoreId getId() {
return id;
}
public void setId(ScoreId id) {
this.id = id;
}
public Integer getPoints() {
return points;
}
public void setPoints(Integer points) {
this.points = points;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
Score other = (Score) obj;
return Objects.equals(id, other.id) && Objects.equals(points,other.points);
}
return false;
}
#Override
public int hashCode() {
return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[id =" + id + ",points = " + points;
}
}
ScoreId.java
#Embeddable
public class ScoreId implements Serializable
{
private Integer user;
#Enumerated(EnumType.STRING)
private Game game;
public ScoreId() {
}
public ScoreId(Integer user, Game game) {
this.user = user;
this.game = game;
}
public Integer getUser() {
return user;
}
public void setUser(Integer user) {
this.user = user;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public enum Game
{
HANGMAN,
TRIS
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
ScoreId other = (ScoreId) obj;
return Objects.equals(user,other.user) && game==other.game;
}
return false;
}
#Override
public int hashCode()
{
return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[user = " + user + ",game = " + game + "]";
}
}
Main.java
public class Main {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("UserJPA");
EntityManager em = factory.createEntityManager();
EntityTransaction et = em.getTransaction();
User demetrio = em.createQuery("SELECT u FROM User u WHERE u.name = 'Demetrio'",User.class).getSingleResult();
et.begin();
em.remove(demetrio);
et.commit();
em.close();
factory.close();
}
}
This is the script to generate db:
CREATE TABLE `user`
(
id INT PRIMARY KEY,
`name` VARCHAR(20) UNIQUE NOT NULL
);
CREATE TABLE score
(
`user` INT,
game ENUM("HANGMAN","TRIS"),
points INT UNSIGNED NOT NULL,
PRIMARY KEY(`user`,game),
FOREIGN KEY (`user`) REFERENCES `user`(id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
I'm using Hibernate as JPA implementation.
I searched for a solution but I did not find anything.
Maybe I'm doing something wrong.
Can you help me?
The implementation I see is absolutly correct, allthou it always can be improoved. The db-design is good. The exception you post can simply not exist but it does. The Database must have a problem. Thats why I asked to post the DDL of the table. I trust in your DDL you posted what makes me think: You did everything right.
What I do is I could only guess.
The table's engine is InnoDB but what is the status of the InnoDB-engine? Is it working? Is it active? Use SHOW ENGINE INNODB STATUS to see the status of InnoDB.
I solved by replacing Integer user of ScoreId with User user with a #ManyToOne annotation.
These are my classes:
User.java
#Entity
#Table(name = "user")
public class User
{
#Id
private Integer id;
#NotNull
#Size(max = 20)
private String name;
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true,mappedBy = "id.user")
private Collection<Score> scores;
public User() {
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
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;
}
public Collection<Score> getScores() {
return scores;
}
public void setScores(Collection<Score> scores) {
this.scores = scores;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
User other = (User) obj;
return Objects.equals(id, other.id) && Objects.equals(name, other.name);
}
return false;
}
#Override
public String toString() {
return getClass().getName() + "[id = " + id + ",name = " + name + "]";
}
#Override
public int hashCode() {
return id!=null ? name!=null ? id.hashCode() + name.hashCode() : 0 : 0;
}
}
Score.java
#Entity
#Table(name = "score")
public class Score
{
#EmbeddedId
private ScoreId id;
#NotNull
private Integer points;
public Score() {
}
public Score(ScoreId id, Integer points) {
this.id = id;
this.points = points;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
Score other = (Score) obj;
return Objects.equals(id,other.id) && Objects.equals(points,other.points);
}
return false;
}
#Override
public int hashCode() {
return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[id =" + id + ",points = " + points + "]";
}
}
ScoreId.java
#Embeddable
public class ScoreId implements Serializable
{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="user",referencedColumnName = "id")
private User user;
#Enumerated(EnumType.STRING)
private Game game;
public ScoreId() {
}
public ScoreId(User user, Game game) {
this.user = user;
this.game = game;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public enum Game
{
HANGMAN,
TRIS
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
ScoreId other = (ScoreId) obj;
return Objects.equals(user,other.user) && game==other.game;
}
return false;
}
#Override
public int hashCode()
{
return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[user = " + user + ",game = " + game + "]";
}
}
Database schema is the same.
In my case there was an Envers used, and on deleteAll() or delete() it tried to insert a record with type 2 (deleted) into corresponding _aud table.
However, when it does so, all the fields of the record appear to be NULL, but in the _aud table one of the columns was marked as "NON-NULL".
Removing the "NON-NULL" from those column in _aud table fixed the issue.
I was working on Spring data Cassandra While creating an entity I am giving the required annotations for fields but when I am giving #Indexed annotation for creating an secondary index in the Schema and I am not able to query on the indexed attribute with out giving Allow Filtering.Could some one please tell me how to create a Secondary Index using Spring data annotations in Cassandra
This is the sample cod that I am using creating a Sprind data Cassandra Entity.#Indexed annotation not creating a secondary index in Cassandra database
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.springframework.data.cassandra.mapping.CassandraType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.Indexed;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.data.cassandra.mapping.UserDefinedType;
import com.datastax.driver.core.DataType;
import com.suntecgroup.xelerate.platform.demo.config.SpringContainer;
import com.suntecgroup.xelerate.platform.demo.store.CustomerCassandraStore;
import com.suntecgroup.xelerate.platform.demo.store.impl.CustomerCassandraStoreImpl;
#Table(value="CustomerCassandra")
public class CustomerCassandra extends CassandraEntity<Integer> {
#PrimaryKey(value="cust_id")
private Integer custId;
#Indexed(value="name")
private String name;
#Indexed(value="email")
private String email;
#Column(value="domain")
private String domain;
#Column(value="category")
private String category;
#Column(value="created_at")
private Date createdAt;
#CassandraType(type=DataType.Name.LIST,typeArguments = { DataType.Name.UDT }, userTypeName = "address_demo_type")
#Column(value="addresses")
private List<Address> addresses;
#Override
public Integer getId() {
return custId;
}
#Override
public void setId(Integer id) {
this.custId = id;
}
public static CustomerCassandraStore getStore() {
return (CustomerCassandraStore) SpringContainer.getBean(CustomerCassandraStoreImpl.class);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public List<Address> getAddresses() {
return addresses;
}
public void setAddresses(Address... addresses) {
LinkedList<Address> addressList = new LinkedList<>();
for(Address addr: addresses) {
addressList.add(addr);
}
setAddresses(addressList);
}
public void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
#UserDefinedType(value="address_demo_type")
public static class Address {
#CassandraType(type = DataType.Name.TEXT)
#Column(value="street_address")
private String streetAddress;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="city")
private String city;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="country")
private String country;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="pincode")
private String pincode;
public String getStreetAddress() {
return streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPincode() {
return pincode;
}
public void setPincode(String pincode) {
this.pincode = pincode;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((city == null) ? 0 : city.hashCode());
result = prime * result + ((country == null) ? 0 : country.hashCode());
result = prime * result + ((pincode == null) ? 0 : pincode.hashCode());
result = prime * result
+ ((streetAddress == null) ? 0 : streetAddress.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (city == null) {
if (other.city != null)
return false;
} else if (!city.equals(other.city))
return false;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
if (pincode == null) {
if (other.pincode != null)
return false;
} else if (!pincode.equals(other.pincode))
return false;
if (streetAddress == null) {
if (other.streetAddress != null)
return false;
} else if (!streetAddress.equals(other.streetAddress))
return false;
return true;
}}
}
It looks like some bug in spring-data-cassandra lib. I'm not able to create index through annotation as well.
I faced a similar issue while creating the schema during test execution (it's not clear how the OP creates the table based on the annotations).
My code was invoking CassandraAdminOperations.createTable() function and I quickly found out that createTable does not include indices, so any queries on the (supposedly) indexed columns were failing. My original code was just:
#Autowired
private CassandraAdminOperations adminTemplate;
#Before
public void createTable() {
adminTemplate.createTable(true, CqlIdentifier.of(DATA_TABLE_NAME), User.class, new HashMap<>());
}
In order to generate the indices based on the annotations, I had to modify my #Before method as:
#Autowired
private CassandraAdminOperations adminTemplate;
#Before
public void createTable() {
adminTemplate.createTable(true, CqlIdentifier.of(DATA_TABLE_NAME), User.class, new HashMap<>());
CassandraPersistentEntity<?> entity = adminTemplate.getConverter().getMappingContext().getRequiredPersistentEntity(User.class);
List<CreateIndexSpecification> indexSpecifications = adminTemplate.getConverter().getMappingContext().getCreateIndexSpecificationsFor(entity);
indexSpecifications.forEach(is -> adminTemplate.getCqlOperations().execute((CreateIndexCqlGenerator.toCql(is))));
}
Table tableAnno=AnnotationUtils.getAnnotation(MessagePO.class, Table.class);
String tableName=tableAnno.value();
log.info("initial table{}",tableName);
/**
* create table
*/
adminTemplate.createTable(true, CqlIdentifier.fromCql(tableName), MessagePO.class, null);
Field[] fields = MessagePO.class.getDeclaredFields();
/**
* create index
*/
CqlOperations cqlOperations=adminTemplate.getCqlOperations();
Arrays.stream(fields).forEach(field -> {
Indexed indexed = AnnotationUtils.getAnnotation(field, Indexed.class);
Column column = AnnotationUtils.getAnnotation(field, Column.class);
if (indexed != null && column != null) {
String indexVal = indexed.value();
String indexSql=String.format("CREATE INDEX %s on %s(%s)",indexVal,tableName,column.value());
cqlOperations.execute(String.format("DROP INDEX if EXISTS %s",indexVal));
cqlOperations.execute(indexSql);
log.info("create index {}",indexSql);
}
});
this is my initial index code, it's work well
I have an EJB application in where I am using Entity beans for database. I have to Entity beans having unidirectional one to one relation, JobPositionEntity and CandidateEntity.
Here is CandidateEntity
#Entity
public class CandidateEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long meritNumber;
private String seatNumber;
private String candidateName;
private String gender;
public Long getMeritNumber() {
return meritNumber;
}
public void setMeritNumber(Long meritNumber) {
this.meritNumber = meritNumber;
}
public String getSeatNumber() {
return seatNumber;
}
public void setSeatNumber(String seatNumber) {
this.seatNumber = seatNumber;
}
public String getCandidateName() {
return candidateName;
}
public void setCandidateName(String candidateName) {
this.candidateName = candidateName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
#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 CandidateEntity)) {
return false;
}
CandidateEntity other = (CandidateEntity) 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 "com.nisheeth.config.ejb.entity.CandidateEntity[ id=" + id + " ]";
}
}
Here is JobPositionEntity
#Entity
public class JobPositionEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToOne(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.ALL)
private CandidateEntity candidate;
#ManyToOne(fetch = FetchType.EAGER)
private SeasonEntity season;
public SeasonEntity getSeason() {
return season;
}
public void setSeason(SeasonEntity season) {
this.season = season;
}
public CandidateEntity getCandidate() {
return candidate;
}
public void setCandidate(CandidateEntity candidate) {
this.candidate = candidate;
}
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
#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 JobPositionEntity)) {
return false;
}
JobPositionEntity other = (JobPositionEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "com.nisheeth.config.ejb.entity.JobPositionEntity[ id=" + id + " ]";
}
}
I want to select candidates which are not in JobPositionEntity. I have this query which did not work for me:
select ce.candidateName, ce.id from JobPositionEntity jp left join jp.candidate ce where ce <> null
Can anyone help write this query? Thanks in advance.
you can use a SubQuery
select c from Candidate c where c.id not in
(select jp.candidate.id from JobPositionEntity jp)
for more information:
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html#queryhql-subqueries
I'm trying to map a bidirectional ManyToMany relationship between the class Problem and the class Domain. Therefore the persistency unit creates a join table in the database, but it seems no entry pops up in the database.
Here's some code:
The class Problem
package domain;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#XmlRootElement
public class Problem implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private User user;
private String description;
private int maxprice;
private int priority;
private Solution solution;
private Location location;
private List<Domain> domains;
#Id
//#GeneratedValue(strategy = GenerationType.AUTO)
#SequenceGenerator(name="User_Seq", allocationSize=25)
#GeneratedValue(strategy=SEQUENCE, generator="Problem_Seq")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToOne
//#JoinColumn(name="user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getMaxPrice() {
return maxprice;
}
public void setMaxPrice(int maxprice) {
this.maxprice = maxprice;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="solution_id")
public Solution getSolution() {
return solution;
}
public void setSolution(Solution solution) {
this.solution = solution;
}
#ManyToOne
#JoinColumn(name="location_id")
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
#ManyToMany
#JoinTable(name="problem_domain",
joinColumns={#JoinColumn(name="problem_id", referencedColumnName="ID")},
inverseJoinColumns={#JoinColumn(name="domain_id", referencedColumnName="ID")})
public List<Domain> getDomains() {
return domains;
}
public void setDomains(List<Domain> domains) {
this.domains = domains;
}
public void addDomain(Domain domain){
//this.domains.add(domain); //Throws NullpointerException om een of andere reden.
}
#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 Problem)) {
return false;
}
Problem other = (Problem) 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 "domain.Problem[ id=" + id + " ]";
}
}
The class Domain
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package domain;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#XmlRootElement
public class Domain implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private List<Problem> problems;
private List<Domain> subDomains;
private Domain superDomain;
#Id
#SequenceGenerator(name="Dom_Seq", allocationSize=25)
#GeneratedValue(strategy=SEQUENCE, generator="Dom_Seq")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToMany(mappedBy = "domains")
public List<Problem> getProblems() {
return problems;
}
public void setProblems(List<Problem> problems) {
this.problems = problems;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="superdomain_id")
public List<Domain> getSubDomains() {
return subDomains;
}
public void setSubDomains(List<Domain> subDomains) {
this.subDomains = subDomains;
}
public Domain getSuperDomain() {
return superDomain;
}
public void setSuperDomain(Domain superDomain) {
this.superDomain = superDomain;
}
#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 Domain)) {
return false;
}
Domain other = (Domain) 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 "domain.Domain[ id=" + id + " ]";
}
}
the code where we add a problem and a domain to the database
Problem problem = new Problem();
Domain domain = new Domain();
domain.setName(domainString);
domainFacade.create(domain);
problemFacade.create(problem);
problem.addDomain(domain);
problemFacade.edit(problem);
and a little visual explanation of the DB
Do you try to save List of domain to problem?
Example of code:
Problem problem = new Problem();
Domain domain = new Domain();
domain.setName(domainString);
domainFacade.create(domain);
List<Domain> domains = new ArrayList<Domain>();
domains.add(domain);
problem.setDomains(domains);
problemFacade.create(problem);
As #Neil Stockton and others said, the answer to my problem was that I had to have an addMethod that simply added the object to the list.
I have a Spring MVC application that handle Users and Structures that can hosts one or more User.
I'm using Hibernate for the persistence and I'm having some issues with the One-To-Many relation between User and Structure.
This is my User model:
#Entity
#Table(name="USERS")
public class User extends DatabaseEntity {
#Id #GeneratedValue
private Long id = 0L;
#Column
#NotEmpty
private String firstName;
#Column
private String lastName;
#Column
private Date birthDate;
#Column
private String nation;
#Column
private String town;
#Column
private String idNumber;
#Column(unique = true)
private String email;
#Column String resetPasswordToken = "";
#Column
private String password;
#Column
private String avatarUrl;
#Column #Enumerated(EnumType.STRING)
private Role role;
#ManyToOne
#JoinColumn(name = "STRUCTURE_ID")
#Cascade({CascadeType.DETACH})
private Structure structure;
public enum Role {
ADMINISTRATOR,
SPECIALIST,
PATIENT,
DOCTOR,
CARE_GIVER
}
public User() {
birthDate = new Date();
}
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 Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public Set<Group> getGroups() {
return null;
}
public void setGroups(Set<Group> groups) {
}
public Set<Group> getCreatedGroups() {
return null;
}
public void setCreatedGroups(Set<Group> createdGroups) {
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<HangoutUser> getHangoutUsers() {
return null;
}
public void setHangoutUsers(Set<HangoutUser> hangoutUsers) {
}
public String getResetPasswordToken() {
return resetPasswordToken;
}
public void setResetPasswordToken(String resetPasswordToken) {
this.resetPasswordToken = resetPasswordToken;
}
public Group getStructure() {
return structure;
}
public void setStructure(Structure structure) {
this.structure = structure;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
if (!email.equals(user.email)) return false;
if (!id.equals(user.id)) return false;
return true;
}
#Override
public int hashCode() {
Long res = id;
if(id == null)
res = 0L;
int result = res.hashCode();
result = 31 * result + email.hashCode();
return result;
}
}
And this is my Structure model:
#Entity
#Table(name = "STRUCTURES")
public class Structure extends DatabaseEntity {
#Id #GeneratedValue
Long id = 0L;
#Column
String name;
#Column
String address;
#Column
String city;
#Column
String state;
#OneToMany(mappedBy = "structure", fetch = FetchType.EAGER)
#Cascade({CascadeType.DELETE})
Set<User> users = new HashSet<User>();
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
public String getState()
{
return state;
}
public void setState(String state)
{
this.state = state;
}
public Set<User> getUsers()
{
return this.users;
}
public void setUsers(Set<User> users)
{
this.users = users;
}
}
My issue is that when I try to find all the Users with the value STRUCTURE_ID evaluated, I get an Hibernate Exception, like this:
org.springframework.orm.hibernate3.HibernateSystemException: Found two representations of same collection: it.amtservices.livinglab.model.Group.users; nested exception is org.hibernate.HibernateException: Found two representations of same collection: it.amtservices.livinglab.model.Structure.users
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:690) ...
What should I do to solve this problem? I have already tried many ways but nothing solved.
I paste the abstract repository implementation for the UsersRepository and StructureRepository:
#Transactional
public abstract class AbstractRepository<Model extends DatabaseEntity>
{
Logger logger = Logger.getLogger(this.getClass().getSimpleName());
#PersistenceContext
EntityManager em;
protected Class<Model> ModelClass;
protected List<Model> findBy(String parameterName, Object parameterValue)
{
Query q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t where t." + parameterName + " = :" + parameterName);
q.setParameter(parameterName, parameterValue);
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
protected List<Model> findBy(Map<String, Object> parameters)
{
String whereClause = "";
for (String key : parameters.keySet())
{
if (!whereClause.equals("")) whereClause += " and ";
whereClause += "t." + key + " = :" + key;
}
Query q = null;
try
{
q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t where " + whereClause);
}
catch (Exception e)
{
e.printStackTrace();
}
for (String key : parameters.keySet())
{
q.setParameter(key, parameters.get(key));
}
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
protected Model findOneBy(String parameterName, Object parameterValue)
{
List<Model> results = findBy(parameterName, parameterValue);
if (results != null && results.size() > 0) return results.get(0);
return null;
}
protected Model findOneBy(Map<String, Object> parameters)
{
List<Model> results = findBy(parameters);
if (results != null && results.size() > 0) return results.get(0);
return null;
}
public Model findOne(Long id)
{
return findOneBy("id", id);
}
public List<Model> findAll()
{
Query q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t");
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
public boolean save(Model model)
{
try
{
Model newModel = em.merge(model);
if (model.getId() == 0L) model.setId(newModel.getId());
}
catch (Exception e)
{
logger.error(ModelClass.getSimpleName() + "Repository: " + e.getMessage());
return false;
}
return true;
}
public void save(List<Model> models)
{
for (Model model : models)
{
save(model);
}
}
public void delete(Model model)
{
delete(model.getId());
}
public void delete(Long id)
{
beforeDelete(findOne(id));
try
{
Query q = em.createQuery("delete from " + ModelClass.getSimpleName() + " t where t.id = :id").setParameter("id", id);
q.executeUpdate();
}
catch (Exception e)
{
logger.error(ModelClass.getSimpleName() + "Repository: " + e.getMessage());
}
}
public void delete(Collection<Model> models)
{
for (Model model : models)
{
delete(model.getId());
}
}
public void deleteAll()
{
for (Model model : findAll())
{
delete(model);
}
}
public abstract void beforeDelete(Model model);
public List<Model> find(List<Long> ids)
{
List<Model> models = new ArrayList<Model>();
for (Long id : ids)
{
Model model = findOne(id);
if (model != null) models.add(model);
}
return models;
}
}
Thank you!