Hibernate insert with single column table problem - java

I'm using Hibernate with a SQLite database. I have the following class :
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class Authority {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int idAuthority;
(...)
I then have a class Author, that extends Authority and add 4 or 5 fields.
When I try to save an Author object, Hibernate generates the following request :
Hibernate: insert into Authority values ( )
And sqlite doesn't like that.
If I add a dummy String field, like "private String test" and set this property in the constructor, everything works fine.
I'm quite new to hibernate, so I'm not sure how to proceed. Do you have any idea ?
Edit : As requested, the mapping of the Author class :
#Entity
#Table(name="Authors")
#PrimaryKeyJoinColumn(name="idAuthority")
public class Author extends Authority {
#Column(name = "firstName")
protected String firstName;
#Column(name = "lastName")
protected String lastName;
#Column(name = "alias")
protected String alias;
(...)
}
Edit : As requested (bis), the insert code :
public void save(Object data) {
currentSession.saveOrUpdate(data);
}
Nothing fancy...
And to give you more possible leads, here is the database schema :
create table Authority (idAuthority integer, primary key (idAuthority))
create table Authors (alias varchar, firstName varchar,
lastName varchar, idAuthority bigint not null, primary key (idAuthority))
N.B. : in SQLite, an integer that is primary key is automatically set to AUTO-INCREMENT.
The Exception raised is this one :
java.sql.SQLException: near ")": syntax error
The request should be more like : insert into Authority values (NULL) to let SQLite do its auto-increment, not this weird "insert into Authority values ()".
Edit : This is definetely a problem with the SqlLite for Hibernate package. I just tried with Hsqldb, and it gives me a proper query :
insert into Authority (idAuthority) values (default)
(Then it fails too, but for very different reasons :p ).
I'm not sure there is a solution to this problem... other than using a different DB.

If you use InheritanceType.JOINED your table associated with class Authority must contain column associated with idAuthority and your table associated with class Author must contain column associated with idAuthority that is a foreign key to the primary identifier in table which presents Authority. It's required for table relations accociation

Try Overriding the ID.
#Entity
#Table(name="Authors")
#PrimaryKeyJoinColumn(name="idAuthority")
#AttributeOverride(name="idAuthority", column=#Column(name="id"))
public class Author extends Authority {
#Column(name = "firstName")
protected String firstName;
#Column(name = "lastName")
protected String lastName;
#Column(name = "alias")
protected String alias;
(...)
}

Related

Manage unique fields insertion with hibernate

I'm working on a JAVA project and need to insert an entity in my DB using Hibernate but the fields need to be inserted only once.
I have this ProjectEntity class that I need to insert to my database :
#Entity
#Setter
#Getter
public class ProjectEntity extends PanacheEntity {
private String projectname;
private String projectkey;
}
My projectentity table looks like this :
CREATE TABLE projectentity
(
id BIGINT NOT NULL
CONSTRAINT project_pkey
PRIMARY KEY,
projectname TEXT,
projectkey TEXT,
);
I tried to put the fields in the table as unique but obviously it is not enought as I get an error when I'm trying to insert the same fields and it blocks the execution of my program.
I want to know how can I manage the insertion of the project entity once when a new project is specified and then not do it again if the project already exists in my database.
You can use #Column for every fields and set unique=true .
example :
#Column (name "projectname",nullable = false, unique = true )
private String projectname;

How to implement deletion of user?

I’m developing my test project that presents library. As far as I develop it, I meet questions continuously.
Could you help me with one of them?
My model design includes User and LeasingHistory entities, so when user borrows a book LeasingHistory table fills with corresponding record.
create table USER
(
ID BIGINT not null serial primary key,
ADDRESS VARCHAR(255) not null,
DOCUMENT_ID VARCHAR(255) not null,
FIRST_NAME VARCHAR(255) not null,
SUR_NAME VARCHAR(255) not null
);
create table LEASING_HISTORY
(
ID BIGINT not null serial primary key,
BOOK_INSTANCE_ID BIGINT not null,
USER_ID BIGINT not null,
START_DATE DATE(10),
ARRANGED_END_DATE DATE(10),
ACTUAL_END_DATE DATE(10),
foreign key (BOOK_INSTANCE_ID) references BOOK_INSTANCE,
foreign key (USER_ID) references USER
);
Now I have to implement user deletion. How should I do it? How is it implemented in Google, Facebook or in StackOverFlow?
I don’t think that delete orphans is appropriate strategy in this case because history shouldn’t be cleaned up.
I suppose I can add isActive field to User table. In this case I can clear personal info and assign isActive = false when user presses “Delete Account” button.
What are your thought about it?
UPDATE:
I think that an user should have a possibility to recover his account thus in this case #killjoy option is better. Can you check me, do I understand it correctly? I've introduced additional table UserInternalData and in case of user deletion I will clear all data (besides id) from User entity and set isDeleted to true and dateStamp to current date in 'UserInternalData'
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#NoArgsConstructor
#AllArgsConstructor
#Getter
#EqualsAndHashCode
#ToString
class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String surName;
#JsonFormat(pattern="yyyy-MM-dd")
private LocalDate dateOfBirth;
}
#Entity
#NoArgsConstructor
#Getter
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
public final class User extends Person {
#Builder
public User(Long id, String firstName, String surName, LocalDate dateOfBirth, String documentId, String address) {
super(id, firstName, surName, dateOfBirth);
this.documentId = documentId;
this.address = address;
}
private String documentId;
private String address;
}
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Getter
#EqualsAndHashCode
#ToString
public final class UserInternalData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne
private User user;
boolean isDeleted;
#JsonFormat(pattern="yyyy-MM-dd")
private LocalDate dateStamp;
}
Am I right?
A few approaches to consider.
Add an isActive column (or equivalently, an isDeleted column) to the USER table. Clear (or set) the bit when the user is deleted. You probably also want to wipe out other sensitive info. This leaves open the possibility of reactivating deleted users in the future.
Replace the USER_ID field in all of the affected rows in LEASING_HISTORY with a special reserved ID that represents a deleted user (possibly with a name like "Deleted User").
As per #killjoy, normalize the two tables by adding a third table that relates USER_ID to BOOK_INSTANCE_ID, and remove the USER_ID column from LEASING_HISTORY. Then you can simply delete the affected rows from this third table without losing the book leasing history.
Addendum
On second thought, (3) might not be such a good approach. The idea was to separate the USER_ID foreign key out into a separate table, but this does not solve the dangling deleted foreign key problem.
Perhaps a more workable approach is:
Do not constrain USER_ID to be a foreign key. That way, you can safely delete USER rows without needing any cleanup at all. Of course, you still need to insure referential integrity (programmatically) at the time you create each new LEASING_HISTORY row.
I prefer (1) because you are not deleting any user history, just the sensitive user info.

How to separate data into two tables with Spring Boot?

Now I have two tables, the first table called StudentBase and has three columns: id, firstname and lastname. The second table called ResearchAssistant and has two columns: id and course. I designed the tables like this because there are different kinds of students and research assistant is one of them. The two table could be joint together with the primary key id.
I'm writing an endpoint /researchAssistant and take following content as request body of POST method.
{
"firstname":"Jack",
"lastname":"Peter",
"course":"MATH"
}
What I want is that saving firstname and lastname into StudentBase table and save course into ResearchAssistant table. And generate a same id for both.
The first idea comes to my mind is building 3 model classes: StudentBase(id, firstname, lastname), ResearchAssistant(id, course) and ResearchAssistantMixed(firstname, lastname, course). I use ResearchAssistantMixed class as the request body class. After getting the data I will seperate it into a new StudentBase object and a ResearchAssistant object, then I store them seperately.
This process seems really stupid and the performance should be quite low. Do you have some better ideas? How does Spring Boot deal with such cases? Thank you!
This is a database problem and not a spring-boot problem. This is how I would approach (I'm assuming you're using some relational DB like MySql and hibernate for ORM):
Database Tables:
student_base
- id (primary key)
- first_name
_ last_name
research_assistant
- id (primary key)
- student_base_id (foreign key referencing id of student_base)
- course
You can now have equivalent entity classes in Java (for hibernate):
#Entity
#Table(name = "student_base")
public class StudentBase {
#Id
#Column(name = "id")
private Integer id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
// getters and setters
}
#Entity
#Table(name = "research_assistant")
public class ResearchAssistant {
#Id
#Column(name = "id")
private Integer id;
#ManyToOne(optional = false)
#JoinColumn(name = "student_base_id")
private StudentBase studentBase;
#Column(name = "course")
private String course;
// getters and setters
}
Now in your DAOs, you don't need to do much, just persist a student_base record and use the returned object to persist a research_assistant record. For example:
StudentBase studentBase = persist(new StudentBase(1, "abc", "xyz");
persist(new ResearchAssistant(1, studentBase, "pqr");
You can (and should) have two separate classes to accept the request object of the post API (don't use entity classes to accept request data).

JPA - Error trying to map a shared composite key using IdClass instead of an EmbeddedId

Once you see the Composite Keys and the Entities that use them which I post down in the code block, please refer to the next pseudotable that I need to have in the database for the Address entity:
Address Table:
ADDRESS
-------------------------------
DOCUMENTTYPE INT2 PK
DOCUMENTNR VARCHAR(10) PK
ALIAS VARCHAR(20) PK
FULLADDRESS VARCHAR(100)
...
Entities & Composite Keys:
#Embeddable
public class Document implements Serializable {
private DocumentType documentType;
private String documentNr;
...
#Entity
#IdClass(Document.class)
public class Person {
#Id
private DocumentType documentType;
#Id
private String documentNr;
private String fullName;
...
#Embeddable
public class AddressId implements Serializable {
private DocumentType documentType;
private String documentNr;
private String alias;
...
#Entity
#IdClass(AddressId.class)
public class Address {
#Id
#ManyToOne
private Person person;
#Id
private String alias;
private String fullAddress;
...
NOTE: DocumentType is an enum.
Well, I am trying to have that mapping for the Address entity but it doesn't work, I don't know why. It keeps saying (EclipseLink) that I have the problem that the names and types don't match. I don't understand why if the AddressId IdClass doesn't have the alias attribute (and of course neither the Address entity) then it works like a charm, as well as with the full AddressId IdClass (with the alias attribute) but using EmbeddedId. What I need is to have the Address entity just like I posted.
Where is the mapping error?
Thank you in advance!
I think you must add #Enumerated(EnumType.STRING) to your enum field
Like this:
#Id
#Enumerated(EnumType.STRING)
private DocumentType documentType;
I can't answer your question directly. However, here is an observation that may help:
I think your database schema needs work before you map it to Java. Here are some suggestions:
1: Each and every database table should have one and only one primary key (typically of type long) and the primary key should have no business meaning. No composite keys anywhere. Since there are no composite keys, your original problem is no longer an issue.
2:The primary key is typically named after the table name with ID after it (never use just 'ID' as the name).
Example:
Address
addressID long primaryKey
3: The other fields that you call primary keys should probably be foreign keys (type long with ID after them) referencing other table's primary keys.
4: You need to properly normalize your database tables. Example: the column 'fullAddress' probably should be broken up into streetAddress, city, stateID, countryID, zipcode. Another example: ADDRESS table should contain only address information. Why does it have DOCUMENTTYPE? What does that have to do with addresses?
5: The names of your database tables and columns should be clearly understood. The column 'DOCUMENTNR' doesn't mean anything to me.
6:Your database tables and columns should be nowns, and they typically should be mapped to java classes with the same name. Instead, you have a class called AddressId that apparently maps to Address database table. Rename the class to Address.
7: you need to decide what columns are unique and not nullable.
You can contact your friendly neighborhood Database Admin for help creating your database schema.
The derived id for address must incorporate the id from person, which is document not its components. http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/mappedbyid shows some examples but is aimed more at embeddables, but the concept is the same for idclasses. Try
public class AddressId implements Serializable {
private Document person;
private String alias;

Unique items in Hibernate collections

I have defined a collection in Hibernate like this:
...
public class Item {
...
#ElementCollection
List<Object> relatedObjects;
}
It creates a mapping table with colums item_id and object_id.
The problem is that object_id seems to be unique. In other words I can not have two different items being related to the same object. But that is what I want.
I would like the combination of item_id and object_id to be unique. How do I do that?
That's not what I'm experiencing. For the following entity:
#Entity
public class Person implements Serializable {
#Id
#GeneratedValue
private Integer id;
private String firstName;
private String lastName;
#Enumerated(EnumType.STRING)
private Gender gender;
#ElementCollection
private Set<String> nicknames = new HashSet<String>();
private String dept;
// getters, setters
}
The following tables get created:
create table Person (id integer generated by default as identity, dept varchar(255), firstName varchar(255), gender varchar(255), lastName varchar(255), primary key (id))
create table Person_nicknames (Person_id integer not null, nicknames varchar(255))
alter table Person_nicknames add constraint FK24F0D97B19ACB65E foreign key (Person_id) references Person
There is no unique constraint. But I can't say more without seeing your "Object" class (it's an embeddable class, right?).
PS: ElementCollection can't be a ManyToMany, this is more a OneToMany.

Categories

Resources