quarkus panache and postsgresql sequence error - quarkus

I am trying to build a simple quarkus-panache example using postgresql. Postgres version is 12.2. My quarkus version is 1.3.1.Final. When using the sequence generator, I always get an error like this:
PSQLException: ERROR: relation "hibernate_sequence" does not exist
My entity class is like this:
#Entity
public class Movie extends PanacheEntity {
#Id
#GeneratedValue(generator = "movie_id_seq", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(
name = "movie_id_seq",
sequenceName = "movie_id_seq",
allocationSize = 50
)
private Integer id;
public String title;
public String director;
public String genre;
}
and the corresponding table is this:
create table movie (
id integer primary key,
title varchar(255) not null,
director varchar(255) not null,
genre varchar(50) not null
);
create sequence movie_id_seq increment 50 START 1 MINVALUE 1;
What am I missing?

If you want to use a custom ID strategy, you should extend PanacheEntityBase, not PanacheEntity.

Related

spring data jpa on timestamp field for current date?

I have to query on timestamp field for current date and get only 1 record.
I can write the query like:
#Query("Select i From Log i Where i.createdBy = :userId And DATE(i.createdDate) = CURRENT_DATE")
JPA Entity:
#Entity
#Table(name = "log")
public class Log {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "log_id")
private Long logId;
#Column(name = "address")
private String address;
#Column(name = "created_date", updatable = false)
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(style = "yyyy-MM-dd HH:mm:ss")
private Calendar createdDate;
//SETTERS AND GETTERS
}
TABLE:
CREATE TABLE `log` (
`log_id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`address` VARCHAR(30) NOT NULL,
`created_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`log_id`)
)
ENGINE=InnoDB
;
here i am not able to limit the records,
I know we can limit the records by sending Pageable, but again i have to get the record from list.
Is there any way to do this ?
how can we do it in spring data jpa method name ?
You can use a Spring Data repository to do this like the following:
public interface LogRepository extends JpaRepository<Log, Long> {
// just get one or null
Log findOneByCreatedByAndCreatedDate(Instant createdBy, Instant createdDate);
// get all, but pagable
List<Log> findAllByCreatedByAndCreatedDate(Instant createdBy, Instant createdDate, Pageable pageable);
}
I assume you use Instant as timestamp, but this should also work for the other Java 8 date types or the old Date class.
Within your business logic you can now call:
Log log = logRepository.findOneByCreatedByAndCreatedDate(YOUR_TIMESTAMP, Instant.now());
// or
Log allLogs = logRepository.findOneByCreatedByAndCreatedDate(YOUR_TIMESTAMP, Instant.now(), PageRequest.of(0, 50));

spring sql Invalid column name

getting
com.microsoft.sqlserver.jdbc.SQLServerException: Invalid column name
'partnerIdPartner'.
application.properties:
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Table creation:
CREATE TABLE [partnersystem] (
[idPartnerSystem] INT IDENTITY(1,1) ,
[partner_idPartner] INT NOT NULL DEFAULT NULL ,
[Name] NVARCHAR(45) NULL DEFAULT NULL ,
[Domain] NVARCHAR(45) NULL DEFAULT NULL ,
[Code] NVARCHAR(45) NULL DEFAULT NULL ,
[PartnerSystem_idSystem] INT NOT NULL DEFAULT NULL ,
[UpdateUser] NVARCHAR(45) NULL DEFAULT NULL ,
[UpdateDT] DATETIME NULL DEFAULT NULL ,
CONSTRAINT [partnersystem_PRIMARY] PRIMARY KEY CLUSTERED ([idPartnerSystem]), CONSTRAINT [partnersystem_fk_PartnerSystem_partner] FOREIGN KEY ("partner_idPartner") REFERENCES "partner" ( "idPartner" ) ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT [partnersystem_fk_PartnerSystem_System] FOREIGN KEY ("PartnerSystem_idSystem") REFERENCES "system" ( "idSystem" ) ON UPDATE NO ACTION ON DELETE NO ACTION);
CREATE INDEX [partnersystem_fk_PartnerSystem_partner] ON [partnersystem] ([partner_idPartner]);
CREATE INDEX [partnersystem_fk_PartnerSystem_System] ON [partnersystem] ([PartnerSystem_idSystem]);
JPA Entity:
#Entity
#Table(name = "partnersystem")
public class PartnerSystem {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idPartnerSystem")
private int idPartnerSystem;
#Column(name = "partner_idPartner" )
private int partnerIdPartner;
#Column(name = "Name")
private String name;
#Column(name = "Domain" )
private String domain;
#Column(name = "Code" )
private String code;
#Column(name = "PartnerSystem_idSystem" )
private int partnerSystemIdSystem;
#Column(name = "UpdateUser" )
private String updateUser;
my repository:
#Repository
public interface PartnerSystemRepository extends JpaRepository<PartnerSystem,
Integer>{
public PartnerSystem findByPartnerIdPartner(int partnerIdPartner);
}
executing simple query throws an error.
public List<Object[]> findAllPartnerSystem(int id) {
String test =
"SELECT idPartnerSystem, partnerIdPartner, name, domain, code, partnerSystemId" +
" FROM PartnerSystem " +
"WHERE partnerIdPartner = ?"
;
Query query = em.createNativeQuery(test);
query.setParameter(1, id);
List<Object[]> results = query.getResultList();
for (Object[] row : results) {
}
return results;
}
In native queries you have to use the column name not the property name:
"SELECT idPartnerSystem, partner_idPartner, name, domain, code, PartnerSystem_idSystem" +
" FROM partnersystem " +
"WHERE partner_idPartner=
But I suggest using JPQL queries and not native queries.

Spring Data JPA Hibernate - Extra elements appearing in #ManyToOne relationship

I have some entity classes which have a one-to-many - many-to-one relationship. I am using Spring and Hibernate.
Each TwoWayService has exactly 2 Services in my application.
Excerpts:
#Entity
#Table(name = "two_way_services")
public class TwoWayService {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String name;
#OneToMany(cascade = CascadeType.ALL,
mappedBy = "twoWayService",
fetch = FetchType.EAGER)
private List<Service> services;
public TwoWayService() {
services = new ArrayList<>();
// Add two as default
services.addAll(Arrays.asList(new Service(), new Service()));
}
public void setService1(Service service) {
services.set(0, service);
service.setTwoWayService(this);
}
public void setService2(Service service) {
services.set(1, service);
service.setTwoWayService(this);
}
...
}
#Entity
#Table(name = "services")
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String name;
#ManyToOne(optional = false)
#JoinColumn
private TwoWayService twoWayService;
public void setTwoWayService(TwoWayService twoWayService) {
this.twoWayService = twoWayService;
}
...
}
I am using Derby on the backend. The database schema is like this:
CREATE TABLE two_way_services (
id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
config_name VARCHAR(255) NOT NULL,
name VARCHAR(80),
admin_ip VARCHAR(32) NOT NULL,
connection_state INT NOT NULL
);
CREATE TABLE services (
id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
name VARCHAR(80),
type INT NOT NULL,
ruleset VARCHAR(255) NOT NULL,
two_way_service_id INT,
FOREIGN KEY (two_way_service_id) REFERENCES two_way_services(id) ON DELETE CASCADE
);
The repository interface:
public interface TwoWayServiceRepository extends Repository<TwoWayService, Integer> {
<S extends T> S save(S entity);
...
}
In my unit tests, I find that when I call findOne on a TwoWayService, I find that I have 4 Services instead of 2. Browsing the database directly shows the data as I would expect.
TwoWayService tws1 = repo.findOne(1); // get by id
assertThat(tws1.getServices().size()).isEqualTo(2); // fails, expected:<[2]> but was:<[4]>
Examining it in the debugger I see 4 elements in the services list: the two that I expect, plus 2 extra ones which are copies of the expected. I don't see where these are coming from. Why are these extra objects appearing in the list?
I am not sure but I think, it is because you add 2 services in the constructor and 1 in each setter. This makes 4 in total. You test for the amount of services, is that what you wanted to test?

Hibernate/JPA, field 'accreditation_company_id' doesn't have a default value error

I faced the issue described in the title saving my entity though everything in code and db tables seems ok.
Here is my code:
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "company_id", referencedColumnName = "id")
List<CompanyObject> companyObjects;
}
#Entity
public class CompanyObject {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Enumerated(EnumType.STRING)
ObjectType type;
}
Here is my table definitions:
CREATE TABLE `company` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8
CREATE TABLE `company_object` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`company_id` bigint(20) NOT NULL,
`type` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK__company` (`company_id`),
CONSTRAINT `FK__company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Object I'm trying to save contains the following info:
Company(id=32, companyObjects=[CompanyObject(id=null, type=NEW)])
Here is the code I use to save the object:
Controller method:
#RequestMapping(value = "/company/{id}", method = RequestMethod.POST)
public String editCompany(#PathVariable("id") long companyId,
#ModelAttribute("form") CompanyDto form) {
Company company = companyService.getCompanyById(companyId);
companyService.updateCompany(company, form);
return "redirect:/companies";
}
Service method:
#Transactional
public Company updateCompany(Company company, final CompanyDto form) {
company.getCompanyObjects().clear();
company.getCompanyObjects().addAll(form.getCompanyObjects());
return companyRepository.save(company);
}
Am I getting this right that hibernate automatically generate and populate all the missing ids in these objects? If yes what am I missing and why the error appears?
You have some problems here. Firstly, your table definitions are wrong, check your accreditation_object table, you have a foreign key there which references a column that doesn't exist: company_id should be accreditation_company_id.
(or is it just some copy-paste error?)
Secondly, your entities are wrong, try this way:
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#OneToMany(mappedBy="company", cascade = CascadeType.ALL)
Set<CompanyObject> companyObjects;
}
#Entity
public class CompanyObject {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Enumerated(EnumType.STRING)
ObjectType type;
#ManyToOne
#JoinColumn(name = "company_id")
Company company;
}
Note the #ManyToOne annotation in the CompanyObject. If I understand correctly, you want to assign one or more CompanyObject to a Company, thus you have to have a #ManyToOne annotated Company typed field in the CompanyObject.
Now, if you want to save these objects, first save the Company instance, then iterate over the list of CompanyObjects, set the previously saved company instance, and then save the CompanyObjects, something like this:
Company company = new Company();
companyDao.persist(company);
List<CompanyObject> companyObjects = new ArrayList<>();
// populate the list somehow
// ...
for(CompanyObject obj: companyObjects){
obj.setCompany(company);
companyObjectDao.persist(obj);
}
Your updateCompany method is wrong, you should try something like the above code. (I cannot rewrite your example because it looks like something is missing there. What is CompanyDTO?)
Edit: You can use cascade saving (note: I've updated the Company entity), just be sure to set the Company instance to every CompanyObject instance, like:
#Transactional
public Company updateCompany(Company company, final CompanyDto form) {
company.getCompanyObjects().clear();
company.getCompanyObjects().addAll(form.getCompanyObjects());
for(CompanyObject obj : company.getCompanyObjects()){
obj.setCompany(company);
}
return companyRepository.save(company);
}
I think this should work, but I'm not a 100% sure. Give it a try.

Jpa ManytoMany issue with Spring Boot

I have a postgres database and I am trying to make a simple REST service with Spring Boot. I have a problem with jpa ManytoMany relationship.
Person Entity:
#Entity
#Table(name = "person", schema = "persons")
public class Person implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String email;
#Column
private Integer age;
#ManyToOne
#JoinColumn(name = "country_id", referencedColumnName = "id")
private Country countryOfBirth;
#ManyToMany
#JoinTable(
name="persons_countries_residence",
joinColumns=#JoinColumn(name="person_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="country_id", referencedColumnName="id"))
private List<Country> countriesOfResidence;
// getters and setters and to String method overriden
}
Country Entity:
#Entity
#Table(name = "country", schema = "persons")
public class Country implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
#Column(name = "country_name")
private String name;
#Column(name = "country_code")
private String code;
// getters and setters and to String method overriden
}
The postgres schema is the following:
Person Table:
CREATE TABLE persons.person
(
id serial NOT NULL,
name character varying(50) NOT NULL,
email character varying(40) NOT NULL,
age integer,
country_id serial NOT NULL,
CONSTRAINT id PRIMARY KEY (id),
CONSTRAINT country_id FOREIGN KEY (id)
REFERENCES persons.country (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
Country table:
CREATE TABLE persons.country
(
id serial NOT NULL,
country_name character varying(45) NOT NULL,
country_code character varying(10) NOT NULL,
CONSTRAINT country_id PRIMARY KEY (id)
)
Join table:
CREATE TABLE persons.persons_countries_residence
(
person_id integer NOT NULL,
country_id integer NOT NULL,
CONSTRAINT person_country_id PRIMARY KEY (person_id, country_id),
CONSTRAINT persons_countries_residence_country_id_fkey FOREIGN KEY (country_id)
REFERENCES persons.country (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE NO ACTION,
CONSTRAINT persons_countries_residence_person_id_fkey FOREIGN KEY (person_id)
REFERENCES persons.person (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
When i make an HTTP method call, I don't get the Countries of residence.
Service code:
#RequestMapping(method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public List<Person> getAllPersons() {
retutn jpaPersonRepository.findAll();
}
Any help appreciated.
Maybe, you need to specify a schema name in the join table name:
#JoinTable(
name="persons_countries_residence", schema="persons",
joinColumns=#JoinColumn(name="person_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="country_id", referencedColumnName="id"))
Update your Country class code like :
#Entity
#Table(name = "country", schema = "persons")
public class Country implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
#Column(name = "country_name")
private String name;
#Column(name = "country_code")
private String code;
#ManyToMany(mappedBy = "countriesOfResidence")
private List<Person> persons;
// getters and setters and to String method overriden
}
Although a ManyToMany relationship is always bi-directional on the
database, the object model can choose if it will be mapped in both
directions, and in which direction it will be mapped in. If you choose
to map the relationship in both directions, then one direction must be
defined as the owner and the other must use the mappedBy attribute to
define its mapping. This also avoids having to duplicate the JoinTable
information in both places.
Do you mean that the country list is null? #ManyToMany associations are lazily loaded by default, you need to enable eager-fetching for it to work straight away.
#ManyToMany(fetch = FetchType.EAGER)
The solution is this:
#ManyToMany
#JoinTable(
name="persons_countries_residence", schema = "persons",
joinColumns=#JoinColumn(name="person_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="country_id", referencedColumnName="id"))
private List<Country> countriesOfResidence;
The schema had to be specified at the #JoinTable annotation as well.

Resources