PSQLException: ERROR: syntax error at or near - java

I have what I thought was a straight forward relation in JPA. Looks like this. CompanyGroup:
#Entity
#Table
public class CompanyGroup implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
#Column(name = "name")
private String name;
#JoinColumn(name = "companies")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Company> companies;
}
Company:
#Entity
#Table
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "name")
private String name;
#JoinColumn(name = "users")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<User> users;
#Id
#GeneratedValue
private Long id;
}
User:
#Entity
#Table
public class User {
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "email")
private String email;
#Id
#GeneratedValue
private Long id;
}
I have omitted setters, getters, etc.
This is not working. I'm trying to save a CompanyGroup(Has 2 companies, each company has 2 users, all entities are unique) to a fully empty database.
I persist this using Spring-Data, accessed in a service like this:
#Service
public class ConcreteCompanyGroupService implements CompanyGroupService {
#Autowired
private CompanyGroupRepository repository;
#Transactional
#Override
public void save(CompanyGroup group) {
repository.save(Collections.singleton(group));
}
}
When I try to call this method I receive this:
org.postgresql.util.PSQLException: ERROR: syntax error at or near "User"
Position: 13
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2458)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2158)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:291)
Hopefully I have done something stupid that someone can find quickly. I don't know how to solve this.
EDIT:
The driver in my pom.xml:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1211</version>
</dependency>

Your entity maps across to a table name that is an SQL reserved keyword (User). Sadly for you, your chosen JPA provider does not automatically quote the table name identifier, and so you get exceptions when referring to the table.
Solution is either to quote the table name yourself in the #Table annotation, or change the table name to not be a reserved keyword. Alternatively use a JPA provider that auto-quotes such reserved keywords for you (e.g DataNucleus)

Solution 1: As Pascal mentioned, you have to escape the table name with backslash like:
#Entity
#Table(name="\"User\"")
public class User {
...
}
Solution 2: Rename your table's anme with another name (Users)
#Entity
#Table(name="Users")
public class User {
...
}
Solution 3: Add a suffix to the table's name:
#Entity
#Table(name="APP_User")
public class User {
...
}
Solution 4: Change the entity name, e.g. ApplicationUser
#Entity
public class ApplicationUser {
...
}
The reason
PostgreSQL as some reserved SQL Key Words. For example: ABORT, ALL, ARRAY, CACHE, CUBE, USER, ... Those tokens are in the SQL standard or specific to PostgreSQL

Use the #Table annotation or change your class name from User to something else as User is a reserved keyword in sql.

Related

Java entity modeling with table that relates to several others

I have a doubt about how the modeling of my entity would be. Come on, I have a table in the database that serves to save documents from my system, this table has the columns id, fk_id (element foreign key), fk_table (entity name) and file_name (stores the name of my file) .
I did a lot of research before posting my question here, but I didn't find anything related to it, what would my entities, user, patient and doctor?
DB:
id
fk_id
fk_table
file_name
1
21
user
test1.jpg
2
32
doctor
test2.pdf
3
61
user
test10.pdf
4
100
patient
test5.jpg
Class:
public class User{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String LastName;
// What would a one-to-many relationship look like?
}
public class patient{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
// What would a one-to-many relationship look like?
}
You can use #Where. But be aware that #Where is a Hibernate annotation. It's not in the JPA standard.
For example in the User entity: (I assume that your table is mapped to an entity called Document)
#Where( clause = "fk_table = 'user'")
#JoinColumn(name = "fk_id")
#OneToMany
private List<Document> documents = new ArrayList<>( );
The following is based only on standard JPA annotations. The idea is to create an inheritance hierarchy for the documents table. The base is:
#Entity
#Table(name = "XX_DOCUMENT")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "fk_table")
public abstract class BaseDocument {
#Id
#GeneratedValue(strategy=SEQUENCE)
private Long id;
#Column(name = "file_name")
private String fileName;
}
Here we define that all entities extending this will go to the same table, with the fk_table column to discriminate. The entities extending it are defined as follows:
#Entity
#DiscriminatorValue("doctor")
public class DoctorDocument extends BaseDocument {
#ManyToOne
#JoinColumn(name = "fk_id")
private Doctor doctor;
}
#Entity
#DiscriminatorValue("patient")
public class PatientDocument extends BaseDocument {
#ManyToOne
#JoinColumn(name = "fk_id")
private Patient patient;
}
// and so on
The interesting thing is that we are reusing the column fk_id to point to the right table. From a small experiment, Hibernate seems to not have problems with it. I would suggest that you manage the DB creation another way just to be safe.
The Doctor, Patient etc need not have a common base class, e.g.:
#Entity
#Table(name = "XX_DOCTOR")
public class Doctor {
#Id
#GeneratedValue(strategy=SEQUENCE)
private Long id;
#OneToMany(mappedBy = "doctor")
private Collection<DoctorDocument> documents = new ArrayList<>();
// any doctor-specific fields
}
#Entity
#Table(name = "XX_PATIENT")
public class Patient {
#Id
#GeneratedValue(strategy=SEQUENCE)
private Long id;
#OneToMany(mappedBy = "patient")
private Collection<PatientDocument> documents = new ArrayList<>();
// any patient-specific fields
}
// and so on
You can read a (doctor, patient, ...)'s documents from the relevant collection. You can even query BaseDocument instances based on any criteria.
You can even go ahead and do more fabcy stuff with the Java code. E.g. define an interface HasDocuments:
public interface HasDocuments<D extends BaseDocument> {
Collection<D> getDocuments();
}
Doctor, Patient, ..., implements this, so they can all be treated the same way.

How to stop Hibernate from eagerly fetching a relationship when it is mapped using a column (referencedColumnName) different than the primary key?

I'm mapping a relationship that does not use the entity's primary key. Using "referencedColumnName" with a column different than the primary key causes hibernate to eagerly fetch the association, by issuing an extra select, even when it's tagged with FetchType.LAZY.
My goal is to make it behave like a regular mapping, meaning it wouldn't issue an extra query every time I need to query the main entity.
I have already tried using #LazyToOne(LazyToOneOption.NO_PROXY), which sorts out the problem, but it does not operate well with Jackson's (JSON parsing library) module "jackson-datatype-hibernate5", which skips hibernate lazy proxies when serializing the results.
Here is a scenario almost like the one I have that causes the problem:
Entities:
#Entity(name = "Book")
#Table(name = "book")
public class Book
implements Serializable {
#Id
#GeneratedValue
private Long id;
private String title;
private String author;
#NaturalId
private String isbn;
//Getters and setters omitted for brevity
}
#Entity(name = "Publication")
#Table(name = "publication")
public class Publication {
#Id
#GeneratedValue
private Long id;
private String publisher;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(
name = "isbn",
referencedColumnName = "isbn"
)
private Book book;
#Column(
name = "price_in_cents",
nullable = false
)
private Integer priceCents;
private String currency;
//Getters and setters omitted for brevity
}
Repository (Spring-Data, but you could try directly with the EntityManager):
#Repository
public interface PublicationRepository extends JpaReadRepository <Publication, Long>
{
#Query ("SELECT d FROM Publication d WHERE d.publisher = ?1 ")
Optional <Publication> findByPublisher (String isbn);
}
Thanks
The only way to achieve what you are looking for is by moving the annotatation #Id to the isbn property.
You can leave the #GeneratedValue on the autoincrement property.
Notes:
1 - Make sure that your equals/hc are following the OID(Object ID) on your domain case the "NaturalId" ISBN.
2 - It will be good to ensure if possible on DB level that your natural ID has unique contraint on it.

How to depict joins with #Query annotation in Spring JPA Repository method

I am using Spring-Boot with JPA and a MySQL backend. Now I got quite confused about the repositories Spring-Boot provides. I know these are quite powerful (and seem to be quite useful since they can shorten your code a lot). Still, I do not understand how to represent Joins within them, since the result-set should be a combination of specified attributes in the select of a few Entities.
Now let's assume we have three tables Book, Author, AuthorOfBook, where the last one is simply connecting Book and Author by a combined Primary key. I guess we had the following Java-Classes:
Entity Book:
#Entity
#Table(name="BOOK")
public class Book {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "TITLE")
private String title;
}
Entity Author
#Entity
#Table(name="AUTHOR")
public class Author {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "LASTNAME")
private String lastname;
#Column(name = "FIRSTNAME")
private String firstname;
//Let's assume some getters and setters and a constructor
}
Entity AuthorOfBook:
#Entity
#Table(name="BOOK")
public class Book {
#EmbeddedId
private AuthorOfBookId pk;
}
An Embedded ID
#Embeddable
public class AuthorOfBookId implements Serializable {
private int authorId;
private int bookId;
}
Repository
#Repository
public interface AuthorOfBookRepository extends JpaRepository<,AuthorOfBookId> {
}
Now how would I represent that query:
SELECT b.name, a.firstname, a.lastname from AuthorOfBook ab inner join Book b on b.id = ab.book_id inner join Author a on a.id = ab.author_id where a.lastname = :lastname;
in my repository? I know the signature would need to be like
#Query([the query string from above])
public (...) findAuthorAndBookByAuthorLastname(#Param("lastname") String lastname);
but I cannot make out what Type the return would be like. What is that method returning? (simply AuthorOfBook would not work I guess)
You don't want AuthorOfBook as a separate Entity. Book should have a field of type Author as a #ManyToOne relationship. That way, given any Book, you can find the author's details.
If you want to handle audits fields you can do something like this:
Audit class
#Embeddable
public class Audit {
#Column(name = "created_on")
private Timestamp createdOn;
#Column(name = "updated_on")
private Timestamp updatedOn;
#Column(name = "is_deleted")
private Boolean isDeleted;
//getters and setters
}
AuditListener to update automatically audits fields
public class AuditListener {
private Long loggedUser = 1001L;
/**
* Method to set the fields createdOn, and isDeleted when an entity is persisted
* #param auditable
*/
#PrePersist
public void setCreatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
if (audit == null) {
audit = new Audit();
auditable.setAudit(audit);
}
audit.setIsDeleted(Boolean.FALSE);
audit.setCreatedOn(Timestamp.from(Instant.now()));
}
/**
* Method to set the fields updatedOn and updatedBy when an entity is updated
* #param auditable
*/
#PreUpdate
public void setUpdatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
audit.setUpdatedOn(Timestamp.from(Instant.now()));
}
}
And add this to the entities
#EntityListeners(AuditListener.class)
public class Book implements Auditable {
#Embedded
private Audit audit;

#Column and #Enumerated doesn't work in embeded entity

I have main entity:
#Entity
#Table(name = "partners")
public class Partner {
#ElementCollection
#CollectionTable(
name = "external_login",
joinColumns = #JoinColumn(name = "partner_id")
)
private List<ExternalLogin> externalLogins;
...
}
And ExternalLogin is embeded entity
#Embeddable
public class ExternalLogin {
#Column(name = "type")
#Enumerated(value = EnumType.STRING)
private ExternalLoginType type;
#Column(name = "login")
private String login;
#Column(name = "password_value")
private String passwordValue;
}
public enum ExternalLoginType {
ABC;
}
#Column and #Enumerated not works in ExternalLogin entity.
For example in query will be external_login.passwordValue instead of external_login.password_value.
#Enumerated(value = EnumType.STRING) doesn't work too. Hibernate is trying to get int value of filed instead string.
Can anyone help me?
You misuse annotation #Embeddable. See description in oracle docs https://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html
Defines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entit
#Embeddable annotation makes sense only for singular assotiation fields. Annotating list fields as #Embeddable is wrong.
Just replace
#Embeddable
public class ExternalLogin {
to
#Entity
public class ExternalLogin {
I had exactly the same issue just now.
The solution for me ended up being adding
#Access(FIELD)
To the Embeddable object.

Hibernate Search #IndexedEmbedded

I have a similar situation like this one
#Entity
#Indexed
public class Place {
#Id
#GeneratedValue
#DocumentId
private Long id;
#Field( index = Index.TOKENIZED )
private String name;
#OneToOne( cascade = { CascadeType.PERSIST, CascadeType.REMOVE } )
#IndexedEmbedded
private Address address;
....
}
#Entity
public class Address {
#Id
#GeneratedValue
private Long id;
#Field(index=Index.TOKENIZED)
private String street;
#Field(index=Index.TOKENIZED)
private String city;
#ContainedIn
#OneToMany(mappedBy="address")
private Set<Place> places;
...
}
The problem now is the following:
If I change for example the name field in entity Place which entities are going to be re-indexed?
1) Only the name field?
2) The whole Place entity?
3) The whole Place entity and the entities annotated with #IndexedEmbedded?
The one I need for my purpose would be the third. So if it is not standard, could there be any solution to achieve this behaviour?
Fortunately it's really the third, so I was lucky and it works as expected
You can use the following code to re-index the Place Entity manually
public void updateIndex(T entity){
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
fullTextEntityManager.index(entity);
fullTextEntityManager.getSearchFactory().optimize(entity.getClass());
}
Secondly if you are using hibernate you can configure lucene in persistence.xml to automatically update the indexes of the entities that are changed

Categories

Resources