SpringBoot + PostgreSQL "Column does not exist" - java

I have been trying to retrieve all data from the table but getting
"Caused by: org.postgresql.util.PSQLException: ERROR: column tenantenti0_.module_name does not exist"
I have tried all the below still the issue persists:
Adding in application.properties file --> spring.jpa.properties.hibernate.default_schema=${your-default-schema-name}
No camel case issue either in table column name or at code side.
Have mentioned the schema name as well under #Table(name = "tenant_info", schema = "public"), however for me it's public so shouldn't effect only in case of custom schema it needs to be mentioned.
Have tried using #namedQuery in entity class and #query in repository class still the same issue.
Below is my Entity class:
#Entity
#Table(name = "tenant_info", schema = "public")
#NamedQuery(name = "TenantEntity.findAll", query = "SELECT t FROM TenantEntity t")
#ApplicationScope
public class TenantEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
private int id;
#Column(name = "tenant_id")
private String tenantId;
#Column(name = "module_name")
private String moduleName;
#Column(name = "url")
private String url;
#Column(name = "username")
private String userName;
#Column(name = "password")
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
public String getModuleName() {
return moduleName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Below is my Repository class:#Repository
public interface TenantRepository extends JpaRepository<TenantEntity, String> {
public List<TenantEntity> findAll();
public TenantEntity findByTenantId(String tenantId);
public List<TenantEntity> findByModuleName(String moduleName);
}
Have attached the table pic.
CREATE TABLE IF NOT EXISTS public.tenant_info (
id integer NOT NULL,
tenant_id text COLLATE pg_catalog."default" NOT NULL,
module_name text COLLATE pg_catalog."default" NOT NULL,
url text COLLATE pg_catalog."default" NOT NULL,
username text COLLATE pg_catalog."default" NOT NULL,
password text COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT tenant_info_pkey PRIMARY KEY (id)
) TABLESPACE pg_default;

I think that there could be two problems you are facing and I cannot comment so I have to answer just to try to help(Sorry if not useful). I believe that it may not be the schema but I would need you to upload your sql for the table to see it. It seems that it may be column not the table but the problem may be with
#Column(name = "module_name")
private String moduleName;
If you look at your sql if you have quotes in postgres you may have to escape them in your java code for it to work properly. Which would make it
#Column(name = "\"module_name\"")
private String moduleName;
Once again sorry if it isn't helpful But can't comment yet so really hopeful that this will help. When I had schema naming issue it wouldn't even say column doesn't exist but the table as a whole would be missing.

This can be caused because your database schema is not in synced with your Entity class. My advice is to inspect your database schema to see if your table has all the columns you expected. Might be more helpful if you show us your database table ;)

Related

Spring Boot: "Column 'username' cannot be null" on #manytoone join column

I'm trying to post the following json file into mysql database in postman.
{
"rem_month": 3,
"rem_day": 23,
"description": "Happy birthday!",
"username": "mortykrox93"
}
But i keep getting the error "Column 'username' cannot be null"
The app is supposed to allow me to login and add multiple reminders for each user.
Here is the sql files the entities are supposed to model:
user.sql
USE `login-reminder`;
CREATE TABLE `user` (
`email_id` varchar(30) DEFAULT NULL,
`password` varchar(30) DEFAULT NULL,
`username` varchar(30) NOT NULL,
PRIMARY KEY(`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
reminder.sql
USE `login-reminder`;
CREATE TABLE `reminder` (
`rem_num` int(12) NOT NULL,
`rem_month` int(2) DEFAULT NULL,
`rem_day` int(2) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`username` varchar(30) NOT NULL,
PRIMARY KEY(`rem_num`),
FOREIGN KEY(`username`) REFERENCES user(`username`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
Here are the two entity files:
User.java
#Entity
#Table(name="user")
public class User {
#Column(name="email_id")
private String emailId;
#Column(name="password")
private String password;
#Id
#Column(name="username")
private String username;
#OneToMany(mappedBy="theUser", cascade = CascadeType.ALL)
private List<Reminder> reminders;
public User() {
}
public User(String emailId, String password, String username) {
this.emailId = emailId;
this.password = password;
this.username = username;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Reminder.java
#Entity
#Table(name="reminder")
public class Reminder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="rem_num")
private int remNum;
#Column(name="rem_month")
private int remMonth;
#Column(name="rem_day")
private int remDay;
#Column(name="description")
private String description;
#ManyToOne
#JoinColumn(name="username")
private User theUser;
public Reminder() {
}
public Reminder(int remNum, int remMonth, int remDay, String description) {
this.remMonth = remMonth;
this.remDay = remDay;
this.description = description;
}
public int getRemNum() {
return remNum;
}
public void setRemNum(int remNum) {
this.remNum = remNum;
}
public int getRemMonth() {
return remMonth;
}
public void setRemMonth(int remMonth) {
this.remMonth = remMonth;
}
public int getRemDay() {
return remDay;
}
public void setRemDay(int remDay) {
this.remDay = remDay;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Here is the restcontroller.
ReminderController.java
#RestController
public class ReminderController {
#Autowired
private ReminderRepository reminderRepository;
#GetMapping("/reminders")
public List<Reminder> getAllReminders() {
return reminderRepository.findAll();
}
#PostMapping("/reminders")
#CrossOrigin(origins = "http://localhost:4200")
public Reminder createReminder(#RequestBody Reminder reminder) {
return reminderRepository.save(reminder);
}
}
If anyone can help I would appreciate it. Not sure if my entities are matching up with my sql statements, any suggestions would help.
Check your reminder sql, it's username field is set as not null.
The binding is with the User object. So, in your json, it you should send the user like this:
{
"rem_month": 3,
"rem_day": 23,
"description": "Happy birthday!",
"theUser":{
"username":"mortykrox93",
//and other fields if necessary
}
}
This is occurring because of there is no field named username present in Reminder entity class and you are referring to same class in controller with annotation #requestbody to be bind with the request. Actually during deserialization no valid mapping is present for json field named username. so by default username is being set as null because of its datatype string.
Note: It's better to use separate model/pojo class for binding the request. And then map it to proper entity objects.
First, you need change your json that indicates by #user404:
{
"rem_month": 3,
"rem_day": 23,
"description": "Happy birthday!",
"theUser":
{
"username":"mortykrox93",
//and other fields if necessary
}
}
also, the problem is in jackson deserialize, you need to use the anotation for make the relashionship in jackson (is different that Hibernate/JPA) #JsonBackReference and #JsonManagedReference:
In User entity:
#JsonBackReference
#OneToMany(mappedBy="theUser", cascade = CascadeType.ALL)
private List<Reminder> reminders;
In Reminder Entity:
#JsonManagedReference
#ManyToOne
#JoinColumn(name="username")
private User theUser;
Anyway, is recomended use separated DTO classes for transfer data and add in those the jackson annotation. In the entity only use JPA annotations.

Inner property is not automatically cast in JOOQ

I have table as below:
CREATE TABLE recipes
(
id INT AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
components JSON,
active BOOLEAN NULL DEFAULT TRUE,
PRIMARY KEY (id),
UNIQUE KEY (name)
)
CHARACTER SET "UTF8"
ENGINE = InnoDb;
I have created pojo class like below:
#JsonIgnoreProperties(ignoreUnknown = true)
public class CValueRecipeV2
{
#JsonProperty("components")
#JsonAlias("matcher.components")
#Column(name = "components")
#Valid
private List<CComponentV2> mComponents;
#JsonProperty("name")
#Column(name = "name")
private String name;
public List<CComponentV2> getComponents()
{
return mComponents;
}
public void setComponents(List<CComponentV2> mComponents)
{
this.mComponents = mComponents;
}
public String getName()
{
return mName;
}
public void setName(String mName)
{
this.mName = mName;
}
}
another class
#JsonIgnoreProperties(ignoreUnknown = true)
public class CComponentV2
{
#JsonProperty("shingle_size")
#JsonAlias("shingleSize")
#CShingleField
private Integer mShingleSize;
public Integer getmShingleSize()
{
return mShingleSize;
}
public void setmShingleSize(Integer mShingleSize)
{
this.mShingleSize = mShingleSize;
}
}
Now I am trying to fetch the record from the database using JOOQ.
But I am not able to convert json component string into component class.
I am reading the data from the table as mentioned below:
context.dsl().select(RECIPES.asterisk())
.from(RECIPES)
.where(RECIPES.NAME.eq(name))
.fetchInto(CValueRecipeV2.class);
In the database, I have the following record.
ID name components active
1 a [{"shingle_size=2"}] true
While fetching the data, I am receiving the following error
Caused by: org.jooq.exception.DataTypeException: Cannot convert from {shingle_size=2} (class java.util.HashMap) to class com.ac.config_objects.CComponentV2
I am new to JOOQ. Please let me know if I missing anything.
Thanks in advance.
I have solved my problem using the jooq converter.
var record = context.dsl().select(RECIPES.asterisk())
.from(RECIPES)
.where(RECIPES.NAME.eq(name))
.fetchOne();
record.setValue(RECIPES.COMPONENTS, record.get(RECIPES.COMPONENTS, new CComponentV2Converter()));
var recipe = record.into(CValueRecipeV2.class);
and my converter lools like below:
public class CComponentV2Converter implements Converter<Object, List<CComponentV2>>
{
static final long serialVersionUID = 0;
#Override
public List<CComponentV2> from(Object databaseObject)
{
var componentList = CObjectCaster.toMapList(databaseObject);
List<CComponentV2> cComponentV2s = new ArrayList<>();
componentList.forEach(e -> {
CComponentV2 cComponentV2 = new CComponentV2();
cComponentV2.setmShingleSize(CObjectCaster.toInteger(e.get("shingle_size")));
cComponentV2s.add(cComponentV2);
});
return cComponentV2s;
}
}
jOOQ doesn't understand your #JsonProperty and other annotations out of the box. You will have to implement your own record mapper to support them:
https://www.jooq.org/doc/latest/manual/sql-execution/fetching/pojos-with-recordmapper-provider/

Getting entity from table without having primary key in Hibernate

I'm currently working on a project where I'm trying to get a list of enities from table which does not have a primary key (dk_systemtherapie_merkmale). This table is 1:n related to another table (dk_systemtherapie). See the screenshot for the table structure.
When getting an entry for dk_systemtherapie, the program fetches the Collection "dkSystemtherapieMerkmalesById". However, the first table entry is fetched as often as the number of actual entries in the table is. It never fetches the other entries from dk_systemtherapie_merkmale. I assume it has something to do with the fact that hibernate can't differ between the entries, but I don't know how to fix it.
Table schema
I've created two corresponding entity classes, dk_systemtherapie:
#Entity
#Table(name = "dk_systemtherapie", schema = "***", catalog = "")
public class DkSystemtherapieEntity {
private int id;
private Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById;
#Id
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToMany(mappedBy = "dkSystemtherapieByEintragId")
public Collection<DkSystemtherapieMerkmaleEntity> getDkSystemtherapieMerkmalesById() {
return dkSystemtherapieMerkmalesById;
}
public void setDkSystemtherapieMerkmalesById(Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById) {
this.dkSystemtherapieMerkmalesById = dkSystemtherapieMerkmalesById;
}
}
Here the second one, which is accessing the table without a primary key, dk_systhemtherapie_merkmale:
#Entity #IdClass(DkSystemtherapieMerkmaleEntity.class)
#Table(name = "dk_systemtherapie_merkmale", schema = "***", catalog = "")
public class DkSystemtherapieMerkmaleEntity implements Serializable {
#Id private Integer eintragId;
#Id private String feldname;
#Id private String feldwert;
private DkSystemtherapieEntity dkSystemtherapieByEintragId;
#Basic
#Column(name = "eintrag_id")
public Integer getEintragId() {
return eintragId;
}
public void setEintragId(Integer eintragId) {
this.eintragId = eintragId;
}
#Basic
#Column(name = "feldname")
public String getFeldname() {
return feldname;
}
public void setFeldname(String feldname) {
this.feldname = feldname;
}
#Basic
#Column(name = "feldwert")
public String getFeldwert() {
return feldwert;
}
public void setFeldwert(String feldwert) {
this.feldwert = feldwert;
}
#Id
#ManyToOne
#JoinColumn(name = "eintrag_id", referencedColumnName = "id")
public DkSystemtherapieEntity getDkSystemtherapieByEintragId() {
return dkSystemtherapieByEintragId;
}
public void setDkSystemtherapieByEintragId(DkSystemtherapieEntity dkSystemtherapieByEintragId) {
this.dkSystemtherapieByEintragId = dkSystemtherapieByEintragId;
}
}
I assume the problem is releated to the fact that Hibernate is using the following annotation as the one and only id for fetching data from database.
#Id
#ManyToOne
#JoinColumn(name = "eintrag_id", referencedColumnName = "id")
public DkSystemtherapieEntity getDkSystemtherapieByEintragId() {
return dkSystemtherapieByEintragId;
}
This leads to the problem that when getting more than one entry with the same id (as the id is not unique), you will get the number of entries you would like to but hibernate is always fetching the first entry for this id. So in fact you are getting dublicate entries.
So how to fix this?
According to this question: Hibernate and no PK, there are two workarounds which are actually only working when you don't have NULL entries in your table (otherwise the returning object will be NULL as well) and no 1:n relationship. For my understanding, hibernate is not supporting entities on tables without primary key (documentation). To make sure getting the correct results, I would suggest using NativeQuery.
Remove the Annotations and private DkSystemtherapieEntity dkSystemtherapieByEintragId; (incl. beans) from DkSystemtherapieMerkmaleEntity.java und add a constructor.
public class DkSystemtherapieMerkmaleEntity {
private Integer eintragId;
private String feldname;
private String feldwert;
public DkSystemtherapieMerkmaleEntity(Integer eintragId, String feldname, String feldwert) {
this.eintragId = eintragId;
this.feldname = feldname;
this.feldwert = feldwert;
}
public Integer getEintragId() {
return eintragId;
}
public void setEintragId(Integer eintragId) {
this.eintragId = eintragId;
}
public String getFeldname() {
return feldname;
}
public void setFeldname(String feldname) {
this.feldname = feldname;
}
public String getFeldwert() {
return feldwert;
}
public void setFeldwert(String feldwert) {
this.feldwert = feldwert;
}
}
Remove private Collection<DkSystemtherapieMerkmaleEntity> dkSystemtherapieMerkmalesById; (incl. beans) from DkSystemtherapieEntity.java.
Always when you need to get entries for a particular eintrag_id, use the following method instead of the Collection in DkSystemtherapieEntity.java.
public List<DkSystemtherapieMerkmaleEntity> getDkSystemtherapieMerkmaleEntities(int id) {
Transaction tx = session.beginTransaction();
String sql = "SELECT * FROM dk_systemtherapie_merkmale WHERE eintrag_id =:id";
List<Object[]> resultList;
resultList = session.createNativeQuery(sql)
.addScalar("eintrag_id", IntegerType.INSTANCE)
.addScalar("feldname", StringType.INSTANCE)
.addScalar("feldwert", StringType.INSTANCE)
.setParameter("id", id).getResultList();
tx.commit();
List<DkSystemtherapieMerkmaleEntity> merkmale = new ArrayList<>();
for (Object[] o : resultList) {
merkmale.add(new DkSystemtherapieMerkmaleEntity((Integer) o[0], (String) o[1], (String) o[2]));
}
return merkmale;
}
Call getDkSystemtherapieMerkmaleEntities(dkSystemtherapieEntityObject.getid()) instead of getDkSystemtherapieMerkmalesById().

Hibernate changing my field name

I am practice Hibernate with the following classes and a MySQL database.
#Entity
#Table(name="Student")
public class Student {
#Id
#GeneratedValue
private int student_id;
private String student_name;
#ManyToOne(cascade=CascadeType.ALL)
private StudentAddress address;
#Transient
#Temporal(TemporalType.DATE)
private Date birthDay;
public Student() {
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
public int getStudent_id() {
return student_id;
}
public void setStudent_id(int rollNo) {
this.student_id = rollNo;
}
public String getStudent_name() {
return student_name;
}
public void setStudent_name(String name) {
this.student_name = name;
}
public StudentAddress getAddress() {
return address;
}
public void setAddress(StudentAddress address) {
this.address = address;
}
}
#Entity
#Table(name="student_address")
public class StudentAddress {
#Id
#GeneratedValue
private int address_id;
private String address_detail;
public int getAddress_id() {
return address_id;
}
public void setAddress_id(int address_id) {
this.address_id = address_id;
}
public String getAddress_detail() {
return address_detail;
}
public void setAddress_detail(String address_detail) {
this.address_detail = address_detail;
}
}
I keep getting the following error message from these sql statements:
Hibernate: insert into student_address (address_detail) values (?)
Hibernate: insert into Student (address_address_id, student_name) values (?, ?)
Error Message:
Unknown column '**address_address_id'** in 'field list'
My database has the field name address_id.
Hibernate keeps appending address to address_id and changes the column name. I could probably change the field name from address to address_address_id in my database but what is causing this to happen. Is it a valid behavior in Hibernate and can I change it?
That's the default column name Hibernate uses for #ManyToOne association:
Default (only applies if a single join column is used): The
concatenation of the following: the name of the referencing
relationship property or field of the referencing entity or embeddable
class; "_"; the name of the referenced primary key column. If there is
no such referencing relationship property or field in the entity, or
if the join is for an element collection, the join column name is
formed as the concatenation of the following: the name of the entity;
"_"; the name of the referenced primary key column.
To specify the desired column name:
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="address")
private StudentAddress address;

Simple object persist in Spring + hibernate

I suppose it is not standard way of doing that so any tips will be helpful, here is my code:
#RequestMapping("/register")
public String register(Map<String, Object> map, #ModelAttribute("user") MyUser user) {
if(user.getLogin() == ""){
map.put("user", new MyUser());
}
else{
map.put("user", user);
map.put("result", userService.addMyUser(user));
}
return "register";
}
what cause following error:
org.hibernate.AssertionFailure: null id in org.mypackage.MyUser entry
(don't flush the Session after an exception occurs)
Here is MyUser class:
#Entity
#Table(name="MyUser")
public class MyUser{
#Id
#Column(name="idMyUser")
#GeneratedValue
private Integer id;
#Column(name="login")
private String login;
#Column(name="password")
private String password;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Try changing the strategy and/or generator for the #GeneratedValue, see here and here for details (for example, you could try #GeneratedValue(strategy = GenerationType.IDENTITY). You could also check if your database table is set to generate the primary key values. The exception seems to indicate that the primary key -field is left unset by the current strategy and/or generator.

Categories

Resources