I am having a JPQL query which has to fetch only two fields one integer and a list value. Here I had created a Dto and mentioned the fields that need to be fetched.
//all variables are defined
query = new StringBuilder();
query.append(ReposJPQL.GET_INCIDENTS);
q = em.createQuery(query.toString());
result = q.getResultList();
where query,
GET_INCIDENTS = "SELECT DISTINCT searchDto ("
+ "ih.Id, ih.logs )"
+ "FROM Hdr ih left join ih.logs sl";
searchDto
public class SearchDto implements Serializable {
private static final long serialVersionUID = 1L;
private Integer ID
private List<IncidentStatusLogDto> statusLogs;
public SearchDto () {
}
public SearchDto (Long incidentId, List<IncidentStatusLogDto> statusLogs) {
super();
this.incidentId = incidentId;
this.statusLogs = statusLogs;
}
}
HDR Entity
#Entity
#Table(name="TB_HDR")
public class IncidentHdr implements Serializable {
private static final long serialVersionUID = 1L;
private Id;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.LAZY, mappedBy="incidentHdr")
#JsonManagedReference
private List<Log> logs;
//getters and setters
}
Here I had added the constructor in searchDto as required, still it throws exception.
no appropriate constructor in class: SearchDto]
org.hibernate.hql.internal.ast.DetailedSemanticException: Unable to locate appropriate constructor on class SearchDto]. Expected arguments are: long, java.util.Collection
When I tried with only Id as value and removed the list it working.
You have a couple of errors in the SearchDTO class:
Missing a semicolon in private Integer ID should be private Integer ID;
You are trying to set this.incidentId = incidentId; in the constructor but you don't have defined the variable.
As I don't know if you have missed it or if you want to replace it by the variable ID my proposal of solution is:
public class SearchDto implements Serializable {
private static final long serialVersionUID = 1L;
private Integer ID;
private Long incidentId;
private List<IncidentStatusLogDto> statusLogs;
public SearchDto () {
}
public SearchDto (Long incidentId, List<IncidentStatusLogDto> statusLogs) {
super();
this.incidentId = incidentId;
this.statusLogs = statusLogs;
}
}
Related
I am attempting to connect to my database in a Spring MVC application. There are two tables. Users and Orders, Users has a primary key column: "userID", orders has a composite key from columns: "userID" and "orderID", where userID is a foreign key referencing the "userID" column in the Users table.
Here are my classes:
Order:
#Entity
#Table(name = "Orders")
#IdClass(OrderPK.class)
public class Order implements Serializable{
private static final Long serialVersionUID = 1L;
#EmbeddedId
private OrderPK orderPK;
//other properties
//no args and full args constructor
//getters and setters
//toString
}
OrderPK:
#Embeddable
public class OrderPK implements Serializable {
#Column(name = "orderID")
private Long orderID;
#ManyToOne
#JoinColumn(name = "userID")
private User user;
public OrderPK() {
}
public OrderPK(Long orderID, User user) {
this.orderID = orderID;
this.user = user;
}
public Long getOrderID() {
return orderID;
}
public void setOrderID(Long orderID) {
this.orderID = orderID;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OrderPK)) return false;
OrderPK that = (OrderPK) o;
return Objects.equals(getOrderID(), that.getOrderID()) &&
Objects.equals(getUser(), that.getUser());
}
#Override
public int hashCode() {
return Objects.hash(getOrderID(), getUser());
}
}
User:
#Entity
#Table(name = "USERS")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="USER_SEQUENCE", sequenceName="USER_SEQUENCE")
#GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="USER_SEQUENCE")
#Column(name = "userid")
private Long userId;
//other properties
//no args and full args constructor
//getters and setters
//toString
}
When I try to connect to the database I get the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unable to find properties (orderID, user) in entity annotated with #IdClass:com.ex.evemarketback.domain.Order
...
Caused by: org.hibernate.AnnotationException: Unable to find properties (orderID, user) in entity annotated with #IdClass:com.ex.evemarketback.domain.Order
Any suggestions?
As you are using the #EmbeddedId, you do not need the #IdClass annotation:
#Entity
#Table(name = "Orders")
public class Order implements Serializable{
or if you want to keep the #IdClass:
// #Embeddable - no need for that
public class OrderPK implements Serializable {
private Long orderID;
private Long userId;
...
}
entity:
#Entity
#Table(name = "Orders")
#IdClass(OrderPK.class)
public class Order implements Serializable{
#Id
#Column(name = "orderID")
private Long orderID;
#Id
#Column(name = "userId", insertable=false, updatable=false)
private Long userId;
#ManyToOne
#JoinColumn(name = "userID")
private User user;
My Json looks like following
{
name: "math",
code:null,
description:"Mathematics",
id:null,
name:"math",
noExam:null,
teacher:{
id: "57869ced78aa7da0d2ed2d92",
courseGroup:"LKG",
experties:[{type: "SOCIALSTUDIES", id: "3"}, {type: "PHYSICS", id: "4"}]
},
id:"57869ced78aa7da0d2ed2d92"
}
if you see my entity classes, I have a set of enums in Teacher.java
When I try to post this I get error
JsonMappingException: Can not deserialize instance of com.iris.fruits.domain.enumeration.Experties out of START_OBJECT token
I have tried almost all solutions out there, like DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, but without success.
public class Subject implements Serializable {
// all the other fields
#JoinColumn(name = "teacher_id")
private Teacher teacher;
// getter and setter
}
public class Teacher implements Serializable {
// all the other fields
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
#Enumerated(EnumType.STRING)
#Column(name = "experties")
#JsonProperty("experties")
private List< Experties> experties;
// getter and setter
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Experties implements Serializable {
MATH(1,"MATH"),
SCIENCE(2,"SCIENCE"),
SOCIALSTUDIES(3,"SOCIALSTUDIES"),
PHYSICS(4,"PHYSICS"),
CHEMISTRY(5,"CHEMISTRY");
#JsonSerialize(using = ToStringSerializer.class)
private String type;
#JsonSerialize(using = ToStringSerializer.class)
private Integer id;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
Experties(Integer id, final String type) {
this.id = id;
this.type = type;
}
}
You have this issue because you have a custom serializer in your enum (#JsonFormat(shape = JsonFormat.Shape.OBJECT)). Thus, to solve the issue, you need a custom deserializer.
You can define a custom deserializer using :
#JsonFormat(shape = JsonFormat.Shape.OBJECT) // custom serializer
#JsonDeserialize(using = MyEnumDeserializer.class) // custom deserializer
public enum Experties implements Serializable {
...
}
The custom deserializer being :
public static class MyEnumDeserializer extends JsonDeserializer<Experties> {
#Override
public Experties deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
String type = node.get("type").asText();
return Stream.of(Experties.values())
.filter(enumValue -> enumValue.getType().equals(type))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("type "+type+" is not recognized"));
}
}
Of course, you can have another deserializer implementation (e.g. use the id field instead of the type field, check the coherence between the id and type fields).
Your class should match with the structure of the json. And in your input json shouldn't repeat keys.
I guess you classes, should like below:
public class Subject implements Serializable {
// all the other fields
String name;
String code;
String description;
String id;
String noExam;
#JoinColumn(name = "teacher_id")
private Teacher teacher;
// getter and setter
}
public class Teacher implements Serializable {
// all the other fields
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
#Enumerated(EnumType.STRING)
#Column(name = "experties")
#JsonProperty("experties")
private List< Experties> experties;
String courseGroup;
// getter and setter
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Experties implements Serializable {
MATH(1,"MATH"),
SCIENCE(2,"SCIENCE"),
SOCIALSTUDIES(3,"SOCIALSTUDIES"),
PHYSICS(4,"PHYSICS"),
CHEMISTRY(5,"CHEMISTRY");
#JsonSerialize(using = ToStringSerializer.class)
private String type;
#JsonSerialize(using = ToStringSerializer.class)
private Integer id;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
Experties(Integer id, final String type) {
this.id = id;
this.type = type;
}
}
Add JsonDeserialize annotation to experties setter in Teacher class:
#JsonDeserialize(using = EnumDeserializer.class)
public void setExperties(List experties){
//...
}
You have this issue because you have a custom serializer in your enum #JsonFormat(shape = JsonFormat.Shape.OBJECT). Jackson does not know how to deserialize object from json, into enum. You can create "creator" method to solve this easily:
public enum Experties implements Serializable {
#JsonCreator
public Experties(String type) {
// here you can use "type" attribute from json object to create your Enum instance. If you need, you can also add as parameter "Integer Id", as it is in your enum json representation.
return valueOf(type);
}
}
My problem is when I save a person domiciled the id of the person record is 1 and the address 2 and when I save another record the id of person is 3 and the domicile 4 and so is increased, I want to increase as it should be is to record who is 1 and for of registered prox 1 for registration is 2 and 2 the next 3 and 3 and so on.
Then I leave the source code of the entities, the main, the method to keep and what gives me the console when I create the tables. I'm using netbeans 7.4 and EclipseLink library jpa2.1 and jdbc for sqlite dirver
#Entity
public class Persona implements Serializable {
protected static final long serialVersionUID = 1L;
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
private Long id;
private String nombre;
#OneToOne (cascade = CascadeType.ALL)
private Domicilio domicilio;
public Persona() {
}
public Persona(String nombre) {
this.nombre = nombre;
domicilio= new Domicilio();
}
public Domicilio getDomicilio() {
return domicilio;
}
public void setDomicilio(Domicilio domicilio) {
this.domicilio = domicilio;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
Entity Domicilio:
#Entity
public class Domicilio implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String calle;
public Domicilio() {
}
public Domicilio(String calle) {
this.calle = calle;
}
public String getCalle() {
return calle;
}
public void setCalle(String calle) {
this.calle = calle;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
Method found in the class PersonaJpaController used to save the record
public void guardar(){
persona= new Persona("angel");
persona.getDomicilio().setCalle("alpatacal");
create(persona);
}
This is my main program
public class Pruebaentidades {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("pruebaentidadesPU");
EntityManager em = emf.createEntityManager();// create tables
PersonaJpaController p= new PersonaJpaController(Persistence.createEntityManagerFactory("pruebaentidadesPU"));
p.guardar();
}
}
This is what gives me the console when I create tables
[EL Info]: 2014-01-03 17:27:01.189--ServerSession(24979675)--EclipseLink, version: Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5
[EL Info]: connection: 2014-01-03 17:27:01.379--Not able to detect platform for vendor name [SQLite3]. Defaulting to [org.eclipse.persistence.platform.database.DatabasePlatform]. The database dialect used may not match with the database you are using. Please explicitly provide a platform using property eclipselink.platform.class.name.
[EL Info]: connection: 2014-01-03 17:27:01.446--ServerSession(24979675)--file:/C:/Users/VM/Desktop/Mis Proyectos/Proyectos Netbeans/pruebaentidades/build/classes/_pruebaentidadesPU login successful
[EL Warning]: 2014-01-03 17:27:01.6--ServerSession(24979675)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: near "CONSTRAINT": syntax error
Error Code: 0
Call: ALTER TABLE PERSONA ADD CONSTRAINT FK_PERSONA_DOMICILIO_ID FOREIGN KEY (DOMICILIO_ID) REFERENCES DOMICILIO (ID)
Query: DataModifyQuery(sql="ALTER TABLE PERSONA ADD CONSTRAINT FK_PERSONA_DOMICILIO_ID FOREIGN KEY (DOMICILIO_ID) REFERENCES DOMICILIO (ID)")
for those who have this same problem I want to say that the solution to the problem was to create a sequence for each table and use the strategy generation secuence.
add these statements for each entity allowing me to create a sequence for each table
Entity Persona:
#GeneratedValue (strategy = GenerationType.SEQUENCE, generator = "PERS_SEQ")
#SequenceGenerator ( name = "PERS_SEQ" , sequenceName = "PERS_SEQ")
Entity Domicilio:
#GeneratedValue(strategy = GenerationType.SEQUENCE , generator = "DOM_SEQ")
#SequenceGenerator ( name = "DOM_SEQ" , sequenceName = "DOM_SEQ")
I am trying to store some custom object as a blob in SqlLite db. The object is a field of a class extending Model. All other fields (of primitive types) go successfully in the DB, but the custom one - it is null always.
#Table(name = "data")
public class Data extends Model {
#Column(name = "number")
private int number;
#Column(name = "blob")
private Contact blob;
...
This is how i store the entity
Data data = new Data(0, new Contact(id, name, number));
data.save();
Here is the contact class
public class Contact {
private String id;
private String name;
private String number;
...
I believe a TypeSerializer is needed, so I've created one.
public class ContactSerializer extends TypeSerializer {
private static final String ELEMENTS_DELIMITER = ";";
#Override
public Object deserialize(Object asString) {
String[] afterSplit = ((String) asString).split(ELEMENTS_DELIMITER);
return new Contact(afterSplit[0], afterSplit[1], afterSplit[2]);
}
#Override
public Class<?> getDeserializedType() {
return Contact.class;
}
#Override
public SerializedType getSerializedType() {
return SerializedType.STRING;
}
#Override
public Object serialize(Object asContact) {
Contact temp = (Contact) asContact;
return temp.getId() + ELEMENTS_DELIMITER + temp.getName() + ELEMENTS_DELIMITER
+ temp.getNumber();
}
}
When i query the db I got object with this particular field "Contact" as null always. Where might be the problem? Do I need to specify which is the TypeSerializer for my object? Or the implementation of TypeSerializer I've created is wrong?
You also need to extent Contact from Model:
#Table(name = "contact")
public class Contact extends Model{
#Column(name = "id")
private String id;
#Column(name = "name")
private String name;
#Column(name = "number")
private String number;
}
Now everything should work out of the box. It's a bit late for a response but perhaps I will help someone else.
I have following class as superclass
#Entity
#MappedSuperclass
public class Location implements LocationCapable {
#Basic
private Double latitude;
#Basic
private Double longitude;
#Basic
private List<String> geocells;
#PrePersist
#Transient
private void generateGeoCells() {
geocells = GeocellManager.generateGeoCell(getLocation());
}
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
this.longitude = longitude;
}
public Double getLatitude() {
return latitude;
}
public void setLatitude(Double latitude) {
this.latitude = latitude;
}
#Override
#Transient
#JsonIgnore
public Point getLocation() {
return new Point(latitude, longitude);
}
#Override
#Transient
#JsonIgnore
public String getKeyString() {
return latitude + ":" + longitude;
}
#Override
public List<String> getGeocells() {
return geocells;
}
public void setGeocells(List<String> geocells) {
this.geocells = geocells;
}
}
And another one which inherits from this
But when I try to run JUnit test I got this
Caused by: org.datanucleus.metadata.InvalidMetaDataException: Class Location has application-identity and no objectid-class specified yet has 0 primary key fields. Unable to use SingleFieldIdentity.
at org.datanucleus.metadata.AbstractClassMetaData.determineObjectIdClass(AbstractClassMetaData.java:1032)
at org.datanucleus.metadata.ClassMetaData.populate(ClassMetaData.java:205)
at org.datanucleus.metadata.AbstractClassMetaData.validateSuperClass(AbstractClassMetaData.java:720)
at org.datanucleus.metadata.AbstractClassMetaData.determineSuperClassName(AbstractClassMetaData.java:642)
at org.datanucleus.metadata.ClassMetaData.populate(ClassMetaData.java:193)
at org.datanucleus.metadata.MetaDataManager$1.run(MetaDataManager.java:2317)
at java.security.AccessController.doPrivileged(Native Method)
at org.datanucleus.metadata.MetaDataManager.populateAbstractClassMetaData(MetaDataManager.java:2311)
at org.datanucleus.metadata.MetaDataManager.populateFileMetaData(MetaDataManager.java:2148)
at org.datanucleus.metadata.MetaDataManager.initialiseFileMetaDataForUse(MetaDataManager.java:864)
at org.datanucleus.metadata.MetaDataManager.loadPersistenceUnit(MetaDataManager.java:794)
at org.datanucleus.jpa.EntityManagerFactoryImpl.initialisePMF(EntityManagerFactoryImpl.java:488)
at org.datanucleus.jpa.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:355)
at org.datanucleus.store.appengine.jpa.DatastoreEntityManagerFactory.<init>(DatastoreEntityManagerFactory.java:63)
at org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider.createEntityManagerFactory(DatastorePersistenceProvider.java:35)
at javax.persistence.Persistence.createFactory(Persistence.java:172)
... 67 more
Also I've tried to add in supperclass the key field annotated with #Id but it gives no result for me
You have to have an #Id field, as the message says.
Looks like it was some problem with enhancing or eclipse plugin, no metter after restart of IDE the problem dessapiared. But only this problem with ID. Actually I've faced with another very strange problem related to embedded entities. I have following domain model:
#Entity
public class City {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
#Basic
private String name;
// Entity won't persist if location is not null, requires to persist with
// further update
#Embedded
// #OneToOne(cascade = CascadeType.ALL) it works the same when I add or remove this line
private Location location;
/* getters and setters */
}
#Embeddable
public class Location implements LocationCapable {
#Basic
#NotNull
private Double latitude;
#Basic
#NotNull
private Double longitude;
#Basic
private List<String> geocells;
/* getters and setters */
}
To test it I have following JUnit test case:
#Test
public void testSave() throws Exception {
City city = new City("testCity1", new Location(1d, 1d));
cityDao.persist(city);
assertNotNull(city.getId());
}
cityDao.persist(city) does simply jpaTemplate.persist(object);
And at when I try to persist this entity I got following exception:
Caused by: java.lang.IllegalArgumentException: out of field index :-1
at com.myproject.model.Location.jdoProvideField(Location.java)
at org.datanucleus.state.JDOStateManagerImpl.provideField(JDOStateManagerImpl.java:2585)
at org.datanucleus.state.JDOStateManagerImpl.provideField(JDOStateManagerImpl.java:2555)
at org.datanucleus.store.mapped.mapping.CollectionMapping.postInsert(CollectionMapping.java:91)
at org.datanucleus.store.mapped.mapping.EmbeddedPCMapping.postInsert(EmbeddedPCMapping.java:104)
at org.datanucleus.store.appengine.DatastoreRelationFieldManager.runPostInsertMappingCallbacks(DatastoreRelationFieldManager.java:217)
at org.datanucleus.store.appengine.DatastoreRelationFieldManager.access$200(DatastoreRelationFieldManager.java:48)
at org.datanucleus.store.appengine.DatastoreRelationFieldManager$1.apply(DatastoreRelationFieldManager.java:116)
at org.datanucleus.store.appengine.DatastoreRelationFieldManager.storeRelations(DatastoreRelationFieldManager.java:81)
at org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations(DatastoreFieldManager.java:955)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.storeRelations(DatastorePersistenceHandler.java:546)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPostProcess(DatastorePersistenceHandler.java:304)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects(DatastorePersistenceHandler.java:256)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject(DatastorePersistenceHandler.java:240)
at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent(JDOStateManagerImpl.java:3185)
at org.datanucleus.state.JDOStateManagerImpl.flush(JDOStateManagerImpl.java:4513)
at org.datanucleus.ObjectManagerImpl.flushInternal(ObjectManagerImpl.java:2814)
at org.datanucleus.ObjectManagerImpl.flush(ObjectManagerImpl.java:2754)
at org.datanucleus.ObjectManagerImpl.preCommit(ObjectManagerImpl.java:2893)
at org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:369)
at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:256)
at org.datanucleus.jpa.EntityTransactionImpl.commit(EntityTransactionImpl.java:104)
at org.datanucleus.store.appengine.jpa.DatastoreEntityTransactionImpl.commit(DatastoreEntityTransactionImpl.java:55)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
... 41 more