Failing me to apply update query scripts in Cuba Platform - jpa

I am receiving this error when I apply this update database script.
default expression needed in statement [alter table WATERSCHEME_LOCATION add column LGA_ID integer not null ]
LGA_ID is a column that is associated with Location Table, LGA_ID is set to mandatory. But when I remove the mandatory, I can update the scripts.
#Table(name = "WATERSCHEME_SCHEME_C")
#Entity(name = "waterscheme$Scheme_c")
public class Scheme_c extends BaseIntegerIdEntity {
private static final long serialVersionUID = -5886267876250540580L;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "LGA_NAME_ID")
protected Lga lgaName;"""
this is my location table
/*
* Copyright (c) 2016 water-scheme
*/
package com.company.waterscheme.entity;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import com.haulmont.cuba.core.entity.BaseIntegerIdEntity;
import com.haulmont.chile.core.annotations.NamePattern;
/**
* #author samuel.thampy
*/
#NamePattern("%s|locationName")
#Table(name = "WATERSCHEME_LOCATION")
#Entity(name = "waterscheme$Location")
public class Location extends BaseIntegerIdEntity {
private static final long serialVersionUID = 8201565825728955033L;
#Column(name = "LOCATION_NAME", nullable = false)
protected String locationName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "LGA_ID")
protected Lga lgaId;
public void setLocationName(String locationName) {
this.locationName = locationName;
}
public String getLocationName() {
return locationName;
}
public void setLgaId(Lga lgaId) {
this.lgaId = lgaId;
}
public Lga getLgaId() {
return lgaId;
}
}
Can somebody help me why I should set a default value?

Probably table you are changing is not empty, is it? BTW, which database is used?
You can't just add a non-null column to a table which already has some data in it.
Usual steps how it is usually achieved:
1) Add nullable column
2) UPDATE all existing rows in the table so that they receive some value.
3) Execute "alter table alter column set not null" to set column as non-null.

Another way is to modify your update script. If you use the CUBA Studio then go the Entity panel and press Generate DB scripts as it is shown in the picture below:
Then you will see all database scripts. Find proper scrip that has
alter table WATERSCHEME_LOCATION add column LGA_ID integer not null
statement and add
DEFAULT {DEFAULT_VALUE}
clause, where you can specify id of the Location entity that should be set while altering for null values. Now you can update your database!
P.S. Note that if you run this script on another database it may cause FOREIGN KEY constraint exception, because Location with the default id doesn't exist. To avoid this you can add another statement to the same update script, so that if the default location doesn't exist in your database then insert it with the specified id.

Related

PanacheEntityBase setting by default id as not nullable, even if specifying the reverse

I have an java class set as entity, which is defined as follow:
package com.redhat.bvbackend.player;
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Entity;
import javax.persistence.SequenceGenerator;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Column;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import com.redhat.bvbackend.team.Team;
#Entity
public class Player extends PanacheEntityBase {
#Id
#Column(name = "player_id", nullable = true)
#SequenceGenerator(name = "playerSequence", sequenceName = "playerIdSequence", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "playerSequence")
public Long id;
public String name;
public String familyName;
public int age;
#OneToMany(mappedBy = "name", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
public List<Team> teams;
#NotNull
#Size(min = 1, max = 1, message = "Handed must be either Left or Right")
public String handed;
}
My class extends PanacheEntityBase and I am setting the column to allow nullable entries, and I am creating a generator to automatically increment the player_id for each new entry. My thought is that if a generator is defined, I shouldn't need to set the nullable since the generator already have an initialValue specified. Actually if I see the #column reference or not, it doesn't change I get always the same output. See below.
I would like to create an player as follow:
INSERT INTO player (age,familyname,handed,name) VALUES (25,'foo','x','y');
without the need to specify the id. However when I do so I get:
ERROR: null value in column "player_id" violates not-null constraint
DETAIL: Failing row contains (null, 25, foo, x, y).
What am I doing wrong? Thanks in advance.
Though you have a sequence generator created for that ID as playerIdSequence your column does not have a default value set.
The #GeneratedValue itself will be used within the panache insert sequence itself, and it will set the value of the ID when building the SQL request.
If you want to be able to automatically assign your ID when running raw SQL requests to the database yourself, you should assign a default value to something like nextval('playerIdSequence'). This way, it will get the next number in the sequence.
You can change the table like this:
alter table public.player alter column player_id set default nextval('playerIdSequence');

JPA #Index annotation doesn't work

I want to add index to one of the columns in my table, but it always complained that column is not found, I checked the table, the column exists!
If I removed that index annotation from the entity object, it works fine.
If I change columnList to the field name, eg, columnList="reportOwnerId", it fails with same message: 'database column not found'
how can i make it work? thanks
here is my entity class:
import javax.persistence.Id;
import javax.persistence.Index;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Entity
#Getter
#NoArgsConstructor
#Table(name = "schedules",
indexes = { #Index(name = "SCHEDULE_OWNER_GUID_INDEX", columnList = "report_owner_guid")}
)
public class ReportSchedule extends AbstractTimestampEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Setter
#Column(name = "report_owner_guid", nullable = false, unique = false)
private String reportOwnerId;
...
and here is the error message:
Caused by: org.hibernate.AnnotationException: Unable to create unique key constraint (report_owner_guid) on table schedules: database column 'report_owner_guid' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
at org.hibernate.cfg.Configuration.buildUniqueKeyFromColumnNames(Configuration.java:1682)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1457)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
Later I figured out it might caused by the fact that column is not unique, and I updated the index to :
#Table(name = "schedules",
indexes = { #Index(name = "SCHEDULE_OWNER_GUID_INDEX", columnList = "report_owner_guid", unique = false)}
)
it still failed with the same error.

Duplicate keys with hibernate

I have a Postgres 9.5.5 table named mytable under schema myschema. It does not have a primary key - we missed adding it when the table was created. This is causing rows with duplicate values in id column of table. The only access points to this table are through the save(), update() and delete() methods of the Hibernate 4.3.10 Final entity class. Nobody is manually updating the database far as I know. What part of the code is sending duplicate id column values to the table? The entity class looks like this -
#Entity
#Table(name = "mytable", schema = "myschema")
public class MyTable implements Serializable {
/** Id. */
#Id
#GeneratedValue(generator = "myschema.mytable_seq", strategy = GenerationType.AUTO)
#SequenceGenerator(name = "myschema.mytable_seq", sequenceName = "myschema.mytable_seq")
#Column(name = "id", unique = true, nullable = false)
private int id;
Below is the sequence definition in postgres -
CREATE SEQUENCE myschema.mytable_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 765
CACHE 1;
The hibernate code is something like this (sessionFactory is an autowired instance of org.hibernate.SessionFactory -
#Repository
public class HBMyTableDao extends HBAbstractDAO<MyTable> implements MyTableDao {
public void save(MyTable model) {
sessionFactory.getCurrentSession().save(model);
}
public void saveOrUpdate(MyTable model) {
sessionFactory.getCurrentSession().saveOrUpdate(model);
}
public void update(MyTable model) {
sessionFactory.getCurrentSession().update(model);
}
public void delete(MyTable model) {
sessionFactory.getCurrentSession().delete(model);
}
}
Hibernate requires primary key.
see https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#mapping-declaration-id
Maybe you can add a autogenerated column to the table

renaming JPA Entities from Tables

I am reprograming an application.
The current database has table names like “User” which is a reserved word in the new db so I changed the table name to “NewUser”. I also had to change a few column names. I would like to code it so it imports the new name but changes them immediately in the app back to the reserved word so I don’t have to spend a lot of time re-programming:
Example Code:
#Entity
// NewUser is the new table name but still User below. I would like to keep the user
//as the class name but go after NewUser in the db
public class User implements java.io.Serializable {
private static final long serialVersionUID = -6091824661950209090L;
/** Primary key */
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
// uid is now newuid in the table but again I want to keep uid in the app
//but reference newuid from the db
protected int uid;
public int getUid() {
return this.uid;
}
public void setUid(int uid) {
this.uid = uid;
}
Just add #Table(name = "NewUser") to your entity. It will remap the entity to new table name, but keep User as entity name which is what is used in queries. You will only have to rewrite native queries if you have them, since that is pure SQL. Also, for renaming column names use #Column(name = "newuid").

Spring MVC / Hibernate / Eclipse - Why Automatically Generated Model Files?

I have a Spring MVC based Java project. This project uses hibernate for the ORM. I am also using Eclipse Kepler as an IDE. I have a question about the Model portion of my project. All of the .java files that I have that are the Model files have an equivalent named file that ends in an underscore. These equivalent files ending in the underscore were automatically generated "I think by the IDE". I have no idea why these files got generated and what their purpose is. Can someone shed some light on this and point me in the right direction? I feel this is either an incorrect IDE setting that is causing them to get generated or is being generated due to some configuration setting that I have within my project.
For instance I have a User.java and a User_.java file. I wrote the User.java but not the User_.java. The User_.java was generated automatically. The code for each of these files is below, the first block is the User_.java that was generated automatically.
package com.bah.iaat.model.data;
import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
#Generated(value="Dali", date="2014-04-03T23:00:06.698-0400")
#StaticMetamodel(AnalyticAgenda.class)
public class AnalyticAgenda_ {
public static volatile SingularAttribute<AnalyticAgenda, Integer> id;
public static volatile SingularAttribute<AnalyticAgenda, String> name;
public static volatile SingularAttribute<AnalyticAgenda, String> desc;
public static volatile SingularAttribute<AnalyticAgenda, Integer> userGroupId;
public static volatile SingularAttribute<AnalyticAgenda, String> flag;
}
The next block of code is the code that I wrote:
package com.bah.iaat.model.data;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.NamedQueries;
import org.hibernate.annotations.NamedQuery;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#NamedQueries({#NamedQuery(name = "SelectAllUsers",query = "Select u from User u"),
#NamedQuery(name = "SelectUserByName",query = "Select u from User u where u.name =:uName"),
#NamedQuery(name = "findUserByIdentifier",query = "Select u from User u where u.name =:pId"),
#NamedQuery(name = "findUserIdByName",query = "select u.id from User u where u.name =:pName"),
#NamedQuery(name = "findUserByName",query = "select u from User u where u.name =:pName")})
#Entity
#Table(name="USERS")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="USER_ID")
private Integer id;
#Column(name="USER_NAME", unique=true)
private String name;
#Column(name="LAST_LOGIN")
private Date lastLogin;
#ManyToOne
#JoinColumn(name="USER_GROUP_ID" )
private UserGroup userGroup;
public User() {}
public User(String name, UserGroup userGroup, Date lastLogin){
this.name = name;
this.userGroup = userGroup;
this.lastLogin = lastLogin;
}
.....
}
These classes constitute the metamodel of your persistence context. They are used when you use the JPA2 Criteria API, in order to create type-safe queries, based on identifiers instead of Strings. For example:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> query = builder.createQuery(Person.class);
Root<Person> from = query.from(Person.class);
query.where(criteriaBuilder.equal(person.get(Person_.name), "Doe"));
Using Person_.name instead of "name" guarantees that you're using a field that exists, and makes sure you'll get a compilation error instead of a runtime error if you rename the field name to lastName, for example.