I am trying to run a named query in my bean but unfortunately it wont work. I get the following error.
Problem compiling [SELECT d FROM IncentiveEntity d WHERE name = :name].
[38, 42] The identification variable 'name' is not defined in the FROM clause.
Following is my code in the bean.
String s = "SELECT d FROM IncentiveEntity d WHERE d.name= :%s";
s = String.format(s, "bla");
IncentiveEntity a = (IncentiveEntity) em.createQuery(s,IncentiveEntity.class).getSingleResult();
I have tried it many other ways possible like removing colon in the query, but it wont work and give different errors. I have found many solutions online but nothing worked, I had to post it here following is the code for my entity class if it helps.
#Entity
public abstract class IncentiveEntity {
#Id //Primary Key
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String init_name;
#OneToMany(mappedBy="incfk", fetch=FetchType.EAGER)
private List<BeverageEntity> bvgfk;
public List<BeverageEntity> getbvgfk() {
if(this.bvgfk == null)
return new ArrayList<BeverageEntity>();
else
return new ArrayList<BeverageEntity>(this.bvgfk);
}
/**
* #param rooms the rooms to set
*/
public void getbvgfk(List<BeverageEntity> or) {
this.bvgfk = or;
}
public int getid() {
return this.id;
}
public String getName(){
return init_name;
}
public void setName(String name){
this.init_name = name;
}
}
Related
i'm new to Springboot. I'm trying to implement a simple REST api using :
-Springboot, JPA & rest along with hibernate
I have a 2 tables database, Notebook that contains 1 to many notes
I already setup the 2 tables and relationships. I also created a NotebookRepository and NoteRepository to get basic CRUD operations via the springboot rest. The Database connection and relationships are functionning
but i don't know how to add a new note (it has a notebook_id foreign key which msut NOT be NULL) and everytime i tryto post something along these lines
{
"title:"abc",
"text":"whatever",
"notebook":{
"id":2
}
}
i get this error :
Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'notebook_id' cannot be null
#Entity
#Table(name="notebook")
public class NoteBook {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="notebook", cascade=CascadeType.ALL)
List<Note> notes;
public NoteBook() {
}
public NoteBook(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Note> getNotes() {
return notes;
}
public void setNotes(List<Note> notes) {
this.notes = notes;
}
public void addNote(Note note) {
if(notes == null) {
notes = new ArrayList<>();
}
note.setNotebook(this);
notes.add(note);
}
#Entity
#Table(name="note")
public class Note {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="title")
private String title;
#Column(name="text")
private String text;
#ManyToOne(cascade={CascadeType.MERGE, CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinColumn(name="notebook_id")
private NoteBook notebook;
public Note() {
}
public Note(String title, String text) {
this.title = title;
this.text = text;
}
#RepositoryRestResource(collectionResourceRel = "note", path = "notes")
public interface NoteRepository extends JpaRepository<Note, Integer>{
//No code...
}
#RepositoryRestResource(collectionResourceRel = "notebook", path = "notebooks")
public interface NotebookRepository extends JpaRepository<NoteBook, Integer>{
}
The problem is that the class Note doesn't have a constructor with NoteBook parameter to pass the created NoteBook object to, so the solution is to add this constructor:
public Note(String title, String text, NoteBook noteBook) {
this.title = title;
this.text = text;
this.noteBook = noteBook;
}
and it's enough to send the JSON object as you do, but just be aware of case-sensitivity:
{ "title:"abc", "text":"whatever", "noteBook":{ "id":2 } }
I think you need to add referencedColumnName = "id" for JoinColumn annotation for notebook field in Note class.
Maybe you have problem with IDENTITY generation type. See this problem with null pointer
i have two tables:
area (
id int PK autoincrement
code varchar
)
products (
id int PK autoincrement
area_id int
)
And the objets are defined like this:
class Product {
...
#JoinColumn(name = "area_id", referencedColumnName = "id")
#ManyToOne
#Expose
private Area area;
...
}
This works fine but I want that area to be a String with the code used in the table area column code.
class Product {
...
???
private String area;
...
}
What should be the annotations to make this work?
Thanks!
Try to use a combination of #SecondaryTable and #Column annotations. Something like this:
#Entity
#SecondaryTable(name="area", pkJoinColumns=#PrimaryKeyJoinColumn(name="id", referencedColumnName="area_id"))
class Product {
...
#Column(name="code", table = "area")
private String code;
...
}
If there is some poor soul with the same problem, here is how I did it:
Using transformers. So the field area is defined like this:
#Transformation(fetch = FetchType.EAGER, optional = false)
#ReadTransformer(transformerClass = AreaAttributeTransformer.class)
#WriteTransformers({
#WriteTransformer(
transformerClass = AreaFieldTransformer.class,
column = #Column(name = "area_id", nullable = false))
})
#Expose
private String area;
Then those clases work like this:
AreaAttributeTransformer
public class AreaAttributeTransformer implements AttributeTransformer {
private AbstractTransformationMapping mapping;
#Override
public void initialize(AbstractTransformationMapping abstractTransformationMapping) {
this.mapping = abstractTransformationMapping;
}
#Override
public Object buildAttributeValue(Record record, Object o, Session session) {
for (DatabaseField field : mapping.getFields()) {
if (field.getName().contains("area_id")) {
EntityManager em = MyEntityManagerFactory.getENTITY_MANAGER_FACTORY().createEntityManager();
List results = em.createNamedQuery("Areas.findById")
.setParameter("id", record.get(field))
.getResultList();
if (results.size() > 0)
return ((Area) results.get(0)).getCode();
}
}
return null;
}
}
AreaFieldTransformer
public class AreaFieldTransformer implements FieldTransformer {
private AbstractTransformationMapping mapping;
#Override
public void initialize(AbstractTransformationMapping abstractTransformationMapping) {
this.mapping = abstractTransformationMapping;
}
#Override
public Object buildFieldValue(Object o, String s, Session session) {
if (o instanceof RouSub) {
EntityManager em = MyEntityManagerFactory.getENTITY_MANAGER_FACTORY().createEntityManager();
List results = em.createNamedQuery("Area.findByCode")
.setParameter("area", ((Area) o).getCode())
.getResultList();
if (results.size() > 0)
return ((Area)results.get(0)).getId();
}
return null;
}
}
I have a table that has a bytea column (named 'pdf') and I don't want to always select it, specially when I'm returning a list from the database, due to performance issues.
I use native queries with spring data inside the repository to solve these types of situations before (when I used eclipselink), but with Hibernate, if I don't write all the columns in the query, it throws an exception.
For test purposes, I'm trying to select only the id from the User and I still get the exception.
Example: "SELET user.id FROM user WHERE user.id = '1'"
It throws an exception saying that it did not find name in the ResultSet, if I put name in the SQL, it then says age was not found and so on, until I have to write all the columns in the SQL.
Thanks in advance for any help.
What I have tried already:
Updating/Downgrading Hibernate and Spring Data with no luck.
Creating a new entity with only the columns I need, works, but it's a messy solution for me.
Maybe the problem is the combination of the frameworks I use and the way I use them, if someone wants, I could try to upload my whole project structure.
My code:
Entity
#Entity
#Table(name = "user", schema = "portal")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "pdf")
private byte[] pdf;
#Column(name = "name")
private String name;
#Column(name = "age")
private Integer age;
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public byte[] getPdf() {
return pdf;
}
public void setPdf(byte[] pdf) {
this.pdf = pdf;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#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 Anexo)) {
return false;
}
Anexo other = (Anexo) 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 "br.gov.to.secad.portal.domain.User[ id=" + id + " ]";
}
}
Service
#Service
#Transactional(readOnly = true)
public class UserService implements Serializable {
private static final long serialVersionUID = 1L;
#Autowired
private IUserRepository userRepository;
public UserService() {
}
public User findOne() {
return userRepository.findOneSQL();
}
}
Repository
public interface IUserRepository extends JpaRepository<User, Serializable>, JpaSpecificationExecutor {
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
public User findOneSQL();
}
The exception:
org.postgresql.util.PSQLException: The column name name was not found in this ResultSet.
Solution
The solution is using an array of Object when I want to select anything less than what I've mapped on my Entity class, thats the limitation of Hibernate that I now understand.
So basically, the method will return Object[] and then I can iterate each position and instantiate a new entity of User with these values.
Example:
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
public Object[] findOneSQL();
I have faced the same problem, I know it is late but well there is a solution that I found elegant.
By the Spring documentation you can declare an interface and from here take the fields you want, in my case it has been something similar to this.
The interface to minimize the fields:
public interface CountryMinify {
String getName();
String getNameTranslation();
}
And my JpaRepository
public interface PlanetRepository extends JpaRepository<Planet, Long> {
#Query(value = "select p.name_country as name, p.name_country_translation as nameTranslation from vm_planet p where gid = ?1", nativeQuery = true)
CountryMinify findByCode(String codeCountry);
}
Keep in mind that the columns should be called the same as gos getter. For example: column name_country -> AS name and the getter of the interface is getName()
Try this
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
Integer findOneSQL();
Call the method like so
Integer user = userRepository.findOneSQL();
Edit 1 :
Since you are using native query you wont be able to use Projections which is a great way of accessing only certain entity fields. There is a JIRA ticket which is still under investigation.
Solution
Return List from your repository like so
#Query(value = "SELECT user.id, user.name FROM user WHERE user.id = '1'", nativeQuery = true)
List<Object[]> findOneSQL();
Iterate over the list of Objects and get your specific columns.
List<Object[]> userNative = userRepository.findOneSQL();
for (Object[] obj : userNative) {
System.out.println("User id : " + obj[0]);
System.out.println("User Name : " + obj[1]);
}
I'm encountering a problem when merging an existing parent entity with a new child entity.
Here's the scenario:
Create two new parent's and persist in db.
In parent's table we will have two new entries as follows
ID = 0, NAME = A
ID = 1, NAME = B
Using entitymanager.find() , fetch the parent with ID=0, and create a new child for the parent.
In the child's table, we will have the following entry
ID=0, NAME = CHILD of A, PARENT_ID = 0
Using entitymanager.find() , fetch the parent with ID=1, and create a new child for the parent.
After merging the parent object using entitymanager.merge(), the newly created child get's merge with the existing child with ID = 0.
The entries in child table, becomes ID=0 , CHILD OF PARENT B, PARENT_ID =0.
Why does this happen? Shouldn't it create a new entry for Child ?
The parent entity:
public class ParentEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="PARENT_SEQ")
#SequenceGenerator(sequenceName="PARENT_SEQ",schema="MURTAZA YAHYA", name = "PARENT_SEQ", initialValue=-1)
//#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID",unique=true, nullable=false)
private Integer id;
#Column(name="NAME" , length=150)
private String name;
#OneToMany(mappedBy="parentEntity",cascade={CascadeType.MERGE,CascadeType.PERSIST})
List<ChildEntity> childEntities;
public Integer getId() {
if(id == null)
return null;
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ChildEntity> getChildEntities() {
return childEntities;
}
public void setChildEntities(List<ChildEntity> childEntities) {
this.childEntities = childEntities;
}
}
The Child Entity
public class ChildEntity implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="CHILD_SEQ")
#SequenceGenerator(sequenceName="CHILD_SEQ",schema="MURTAZA YAHYA", name = "CHILD_SEQ" , initialValue=0)
//#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID",unique=true, nullable=false)
private Integer id;
#Column(name="NAME" , length=150)
private String name;
#ManyToOne
#JoinColumn(name="PARENT_ID")
private ParentEntity parentEntity;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ParentEntity getParentEntity() {
return parentEntity;
}
public void setParentEntity(ParentEntity parentEntity) {
this.parentEntity = parentEntity;
}
}
public String AddChildToAnExistingParent(Parent p) {
// TODO Auto-generated method stub
ParentEntity parent = em.find(ParentEntity.class, p.getId());
ChildEntity childEntity = new ChildEntity();
childEntity.setName("INISYA");
childEntity.setParentEntity(parent);
List<ChildEntity> list = new ArrayList<ChildEntity>();
list.add(childEntity);
parent.setChildEntities(list);
em.merge(parent);
return "Success";
}
Any help will be greatly appreciated. Thank you,
As the Parent->Child association is annotated with CascadeType.PERSIST the following code should resolved the described scenario.
public String AddChildToAnExistingParent(Parent p)
{ // TODO Auto-generated method stub
ParentEntity parent = em.find(ParentEntity.class, p.getId());
ChildEntity childEntity = new ChildEntity();
childEntity.setName("INISYA");
childEntity.setParentEntity(parent);
parent.getChildEntities().add (childEntity);
em.persist(parent);// the cascade.persist cause new childs persistence/insert
return "Success";
}
For more details in this answer explains the behavior of EntityManager method merge and persist.
I want to get the maximum value of column relationId from table ElementRelationType
I have written code but its giving error
CriteriaBuilder cb1 = entityManager.getCriteriaBuilder();
CriteriaQuery<ElementRelationTypes> cq1 = cb1.createQuery(ElementRelationTypes.class);
Root<ElementRelationTypes> root = cq1.from(ElementRelationTypes.class);
cq1.select(cb1.max(root.get("relationId")));
select and max both giving error
how to get the integer max value
public class ElementRelationTypes {
private RelationId relationLangPK=new RelationId();
private Country country;
private Status status;
#EmbeddedId
public RelationId getRelationLangPK() {
return relationLangPK;
}
public void setRelationLangPK(RelationId relationLangPK) {
this.relationLangPK = relationLangPK;
}
#Transient
public Integer getRelationId() {
return getRelationLangPK().getRelationId();
}
public void setRelationId(Integer relationId) {
getRelationLangPK().setRelationId(relationId);
}
#Transient
public Language getLanguage() {
return getRelationLangPK().getLanguage();
}
public void setLanguageCode(Language language) {
getRelationLangPK().setLanguage(language);
}
and
public class RelationId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer relationId;
private Language language;
#JoinColumn(name=PersistenseConstants.ELEMENT_RELATION_TYPE_COL_RELATION_ID)
public Integer getRelationId() {
return relationId;
}
public void setRelationId(Integer relationId) {
this.relationId = relationId;
}
#OneToOne
#JoinColumn(name=PersistenseConstants.LANGUAGE_ENTITY_COL_LANG_CODE)
public Language getLanguage() {
return language;
}
public void setLanguage(Language language) {
this.language = language;
}
You didn't post which errors do you receive, so I have to guess.
CriteriaBuilder.max accepts Expression<N> where N extends Number
At the same time Root.get by default returns Path<Object> which is inconvertible to Expression<Number>.
So to make your call to max work you need to specify generic parameter to root.get:
cq1.select(cb1.max(root.<Number>get("relationId")));
here you can replace Number with an actual type of relationId (Long, BigInteger etc.)
UPDATE: #perissf addressed another issue with your code. If you are going to select maximal value (which is numeric) you should declare your CriteriaQuery as a query to Number not ElementRelationTypes