JPA #Index annotation doesn't work - jpa

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.

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');

Unable to create unique key constraint - Make sure that you use the correct column name which depends on the naming strategy in use

The full error message is:
Unable to create unique key constraint (aircraft_series_id, service_enum) on table aircraft_service: database column 'service_enum' 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)
My entity is specified as:
#Entity
#Table(uniqueConstraints = { #UniqueConstraint(columnNames = { "aircraft_series_id", "service_enum" }) })
#Getter
#Setter
#NoArgsConstructor
#ToString
public class AircraftService {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private Integer minimumQuantity;
#NotNull
private Integer maximumQuantity;
#NotNull
private Integer defaultQuantity;
#NotNull
#ManyToOne(optional = false)
#JsonIgnore
private AircraftSeries aircraftSeries;
#NotNull
#Enumerated(EnumType.STRING)
private ServiceEnum serviceEnum;
}
If I comment out the #Table(uniqueConstraints = { #UniqueConstraint(columnNames = { "aircraft_series_id", "service_enum" }) }) annotation then the columns are created and I can see the field names when opening the table under the SQL client.
service_enum
aircraft_series_id
For now I'm running the application against the H2 database.
I could have the application running not throw an exception if the class is boasting the column annotations, as in:
#Column(name = "service_enum")
#ManyToOne(optional = false)
#JoinColumn(name = "service_profile_id")
I don't see why this is the case, as by default, the column names are exactly the same, when attributed by the application itself.

JPA - Eclipselink - InheritanceType.JOINED not doing the correct JOIN

I dont know if this is a bug or there is something I am missing, but there is a problem when you try to use Inheritance.JOINED when the superclass has a composite primary key.
I have the following classes:
(Superclass)
#Entity
#Table(name = "tipos_opciones_misiones")
#IdClass(TipoOpcionMisionId.class)
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "clase", discriminatorType = DiscriminatorType.STRING)
#ReadOnly
public abstract class TipoOpcionMision{
#Id
#ManyToOne
#JoinColumn(name="tipo_mision")
private TipoMision tipoMision;
#Id
#Column(name = "numero")
private int numero;
}
And a child class:
#Entity
#Table(name="tipos_misiones_opciones_comercio_compra")
#DiscriminatorValue("COMERCIO_COMPRA")
public class TipoOpcionMisionComercioCompra extends TipoOpcionMision{
#Column(name="valor")
double valor;
}
When I try to get a list on objects "TipoOpcionMision" the generated SQL ignores that there is a composite key [tipo_mision, numero] and it just uses "t1.numero = t0.numero". There should also be a "t1.tipo_mision= t0.tipo_mision".
SELECT **list of fields***, FROM tipos_misiones_opciones t0, tipos_misiones_opciones_comercio_compra t1 WHERE ((t0.tipo_mision = 'MISION_1') AND ((t1.numero = t0.numero) AND (t0.clase = 'COMERCIO_COMPRA')))
There is no errors, but I get false results because I am getting the values of the first row in the cartesian product.
I have tried to add:
#PrimaryKeyJoinColumns({
#PrimaryKeyJoinColumn(name = "tipo_mision", referencedColumnName = "tipo_mision"),
#PrimaryKeyJoinColumn(name = "numero", referencedColumnName = "numero")
})
But program fails when starting with the following error:
Exception Description: A #PrimaryKeyJoinColumns was found on the annotated element [class TipoOpcionMisionComercioCompra]. When the entity uses a single primary key, only a single (or zero) #PrimaryKeyJoinColumn should be specified.
It seems that for some reason Eclipselink is ignoring tthat the superclass has a composite primary key.

JAP: table column with name id but not primary key

I have a table with the columns vendorid and id (and more, omitted here; using lombok for definition):
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "vendor_store")
public class VendorMeta {
#Id
#Column(name = "vendorid", unique = true)
private String vendorid;
#Column(name = "id", unique = false)
private String id;
}
This is the corresponding repository:
#Repository
public interface VendorMetaRepository extends JpaRepository<VendorMeta, String>, JpaSpecificationExecutor<VendorMeta> {
List<VendorMeta> findByVendorid(String vendorid);
}
I would expect that findByVendorid is returning a single element and findById returns a list, but it's working the opposite way:
Optional vendorMeta = vendorMetaRepository.findById("1");
List vendorMeta2 = vendorMetaRepository.findByVendorid("1");
Both methods return answers for searching vendorid, findbyId is also searching column vendorid.
What do I have to do to get the correct results?
It seems that this is not possible (at least when using lombok). The generated method findById() searches the primary key (whatever the name of this column is) and not the column with the name "id".
It is possible to use any column name for the primary key but not the name "id" for a non-primary-key column.

Failing me to apply update query scripts in Cuba Platform

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.