ON DELETE SET NULL ON UPDATE SET NULL using JPA - jpa

How do i add ON DELETE SET NULL ON UPDATE SET NULL Constraint while creating the table using JPA . Below the entity definition
table
CREATE TABLE `node` (
`id` bigint(20) NOT NULL,
`parentNode_id` bigint(20) default NULL,
PRIMARY KEY (`id`),
KEY `FK1EC1DD0F28AB6BA5` (`parentNode_id`),
CONSTRAINT `FK1EC1DD0F28AB6BA5` FOREIGN KEY (`parentNode_id`) REFERENCES `node` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
#Entity
public class Node {
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "NodeSequence")
private long id;
#ManyToOne(cascade=CascadeType.REMOVE)
#JoinColumn(name = "parentNode_id", nullable = true)
protected Node parentNode = null;
}

It is a bad idea to use the JPA schema generator for this purpose. It is almost always preferable to have DDL scripts that are hand-coded and placed under version control, to manage your database.
Also, setting foreign key values to null via database constraints, will only result in your persistence context having dirty values, unless the JPA provider is aware of the foreign key constraints in the database, and consciously updates the corresponding values in the persistence context to null.
Also, it is unlikely that JPA schema generators support this feature. For instance, Hibernate does not support this yet, and there are multiple feature requests that have been raised, and none of them have been resolved. EclipseLink also does not appear to support this feature.

Related

JPA optional relationship

I'm using EclipseLink.
I have an entity DIDRequest that has a one to Many relationship with DIDAllocation.
The DIDRequest does not always have an associated DIDAllocation (i.e. the DIDAlloction should be optional).
I have the following entity
#Entity
#Table(name = "tblDIDRequest")
public class DIDRequest
{
int id;
#ManyToOne(optional = true)
private DIDAllocation didAllocation;
}
The optional argument doesn't seem to be working as EclipseLink is generating a foriegn key constraint as follows:
CREATE TABLE `tblDIDRequest` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`DIDALLOCATION_ID` bigint(20) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `FK_tblDIDRequest_DIDALLOCATION_ID` (`DIDALLOCATION_ID`),
CONSTRAINT `FK_tblDIDRequest_DIDALLOCATION_ID` FOREIGN KEY (`DIDALLOCATION_ID`) REFERENCES `tblDIDAllocation` (`ID`),
);
How do I modify the annotation so it doesn't generate the foreign key constraint?
Is there a way to have the constraint so if didAllocation exist then there must be a related entity but if it is null we don't care?
This works just like it should!
A required association can be mapped by having a NOT NULL constraint on a column (to make sure it has a value) and also a FOREIGN KEY constraint, to make sure that value corresponds to the ID in another table.
If you have an optional association, you still want a FOREIGN KEY constraint, so you can't just put gibberish into the column. But you don't have the NOT NULL constraint, so NULL indicates "the association is not present".
`DIDALLOCATION_ID` bigint(20) DEFAULT NULL,
This is nullable and has a default value of NULL.
You may also want to set fetch = FetchType.LAZY on the association and explicitly join/eager-fetch it only when you need it - for efficiency. And in general I highly recommend all articles by Vlad Mihalcea to learn more about efficient JPA use: https://vladmihalcea.com/manytoone-jpa-hibernate/

How do I populate a Vaadin 12.0.4 Grid with data/fields from a PostgreSQL 10.5 table or view?

I know there are dozens of tutorials for how to do this across just as many websites, but this is my first time trying to connect a database table to a UI, so when the version of Spring Boot/MyBatis/Vaadin, for example, are different than the one I'm working with, or they use JPA or JDBC instead of MyBatis, I have no idea how to change it to work with my specific situation.
When people say "it's no different than any other method of doing it with " that doesn't help AT ALL, since, as I stated earlier, I've never done it before. Annotations and classes in the code examples of a tutorial get removed and deprecated with every new version with no clear explanation of how to change it to work with the newer version. I've been researching the various APIs (Spring Boot, Vaadin, MyBatis) for about a month and have a vague understanding of what each one does but not how they work together to achieve the desired result of making a UI for a database. I'm just getting really frustrated at how a single deprecated annotation or class in a tutorial can bring the whole thing crashing down. I know that was long-winded but I just wanted you all to understand where I'm coming from. I'm not particularly attached to any single API, just whatever is easiest.
My current dependencies are:
- Maven : 4.0.0
- Spring Boot: 2.1.2.RELEASE
- Vaadin: 12.0.4
- MyBatis Spring Boot Starter: 2.0.0
I got the starter package from Spring Initializr and added the MyBatis dependency later.
I have a PostgreSQL 10.5 database with 17 tables that will eventually be a UI for a store manager to use for things like looking at received inventory shipments, the hours an employee worked, and other tasks.
My database is named 'store', user: 'store', password: 'store' (if it matters).
For example, these are a few of my tables:
CREATE TABLE IF NOT EXISTS supplier (
id SERIAL,
brand VARCHAR(30) NOT NULL,
phone VARCHAR(15) NOT NULL,
address VARCHAR(100) NOT NULL,
CONSTRAINT pk_supplier PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS shipment (
id SERIAL,
shipdate DATE NOT NULL,
shiptime TIME NOT NULL,
status VARCHAR(10) DEFAULT 'arrived' NOT NULL,
sid INT NOT NULL,
CONSTRAINT pk_shipment PRIMARY KEY (id),
CONSTRAINT fk_shipment_supplier FOREIGN KEY (sid)
REFERENCES supplier(id)
);
CREATE TABLE IF NOT EXISTS shipmentcontains (
shipid INT NOT NULL,
iid INT NOT NULL,
quantity INT NOT NULL,
price DEC(6,2) NOT NULL,
CONSTRAINT pk_shipmentcontains PRIMARY KEY (shipid, iid),
CONSTRAINT fk_shipmentcontains_shipment FOREIGN KEY (shipid)
REFERENCES shipment(id),
CONSTRAINT fk_shipmentcontains_item FOREIGN KEY (iid)
REFERENCES item(id)
);
CREATE TABLE IF NOT EXISTS item (
id SERIAL,
itemtype VARCHAR(25) NOT NULL,
itemsize VARCHAR(10) NOT NULL,
price DEC(5,2) NOT NULL,
sid INT NOT NULL,
CONSTRAINT pk_item PRIMARY KEY (id),
CONSTRAINT fk_item_supplier FOREIGN KEY (sid)
REFERENCES supplier(id)
);
CREATE TABLE IF NOT EXISTS employee (
id SERIAL,
lastname VARCHAR(40) NOT NULL,
firstname VARCHAR(40) NOT NULL,
hourlywage DEC(4,2),
manager BOOLEAN DEFAULT false NOT NULL,
CONSTRAINT pk_employee PRIMARY KEY (id)
);
If someone can give me a code example of how to just get one of those to show in a Grid, I'm sure I can figure out how to do the rest of it. I have the connection details in my application.properties file, but I've seen that with newer versions of MyBatis this isn't needed and annotations such as #Update can be used on the SQL statements to replace that. Also, in plain English, what the heck is a Spring Bean? I hope that wasn't too long..or not long enough.
EDIT: Current version of Vaadin 12 is 12.0.4
You are asking quite a lot, so I will try to touch everything a little and nothing too detailed. I hope this helps you getting the ball rolling.
First off, you will need a java class with all fields that you have in the supplier table, annotated with #Entity. The #Table annotation lets you define the Db table name, and it is not necessary if the table is called the same as the class (case insensitive):
#Entity // javax.persistence
#Table(name = "supplier") // javax.persistence
public class Supplier {
#Id // javax.persistence
private Long id;
private String brand;
private String phone;
private String address;
public Supplier(){
}
// public getters and setters for all fields
// omitted for brevity
}
Now that you have a class for your table, you can start with creating a Vaadin Grid for it. This can be done the easiest with Grid<Supplier> supplierGrid = new Grid<Supplier>(Supplier.class);.
Now to fill the grid with items (suppliers). This is done with supplierGrid.setItems(allSuppliers);. But where do allSuppliers come from you ask?
They can be fetched using a Repository. Because the repository will be annotated with #Repository, its a spring component that can be automatically generated by spring and can be Injected/Autowired (i.e. in your view) using #Inject/#Autowired.
Then you simply call List<Supplier> allSuppliers = supplierRepository.findAll() and you have a list of all suppliers from your DB, that you now can put into the grid with the aforementioned supplierGrid.setItems(allSuppliers);
Any class where an instance of it can be injected by spring is a spring-bean, this includes classes annotated with either #Component, #Serivce or #Repository. Entities like Supplier can not automatically be injected by Spring, unless you define this is your #Configuration class:
/* Do this only if you want to inject a Supplier somewhere. */
#Bean
public Supplier supplier(){
/* define here how a default Supplier should look like */
return new Supplier();
}

Update multiple related tables using Spring Data Rest

I have two tables Employee and Address having one-to-one relationship.
CREATE TABLE EMPLOYEE(
ID BIGINT PRIMARY KEY NOT NULL,
EMP_NAME VARCHAR(50) NOT NULL,
PHONE_ID BIGINT,
DELETED BOOLEAN NOT NULL DEFAULT FALSE,
CONSTRAINT CONSTRAINT1 FOREIGN KEY (PHONE_ID)
REFERENCES PHONE (ID)
)
CREATE TABLE PHONE(
ID BIGINT PRIMARY KEY NOT NULL,
PH_NUMBER VARCHAR(20) NOT NULL,
DELETED BOOLEAN NOT NULL DEFAULT FALSE,
)
I am using Spring Data REST.
Q1. I want to expose a single data rest repository method to update DELETED column for both EMPLOYEE and `PHONE.
Something like below:
TestRepository implements CrudRepository{
#Query(value="update both table query", native=false)
public void updateBoth();
}
Q2. Is doing so even possible using Spring data REST.
PLEASE NOTE: I do not want to use native query, i.e. #Query(value="", native="true")
You have to find the balance between using the framework properly and overusing it.
Spring Data REST is to expose your repositories to HTTP but you can't solve everything with it.
The proper way here is to create a custom Controller and implement the functionality you want with proper transaction management to have the data integrity you need.

In a JPA entity hierarchy using InheritanceType.JOINED, all relationships with subclasses results in foreign key constraints on the superclass table

I have the following JPA 2.0 Entities
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
public abstract class BookKeepingParent implements Serializable {
#Id
protected Long Id;
...
}
#Entity
public class Employee extends BookKeepingParent {
private String name;
#ManyToOne
private Role role;
...
}
#Entity
public class Role extends BookKeepingParent {
private String name;
...
}
I want to let JPA generate tables for me, since it makes it easier to install at multiple locations. I would usually expected it to generate this:
CREATE TABLE bookkeepingparent (
id bigint NOT NULL,
dtype character varying(31),
CONSTRAINT bookkeepingparent_pkey PRIMARY KEY (id )
)
CREATE TABLE role (
id bigint NOT NULL,
name character varying(255),
CONSTRAINT role_pkey PRIMARY KEY (id ),
CONSTRAINT fk_role_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id)
)
CREATE TABLE employee (
id bigint NOT NULL,
name character varying(255),
role_id bigint,
CONSTRAINT employee_pkey PRIMARY KEY (id ),
CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id),
CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES role (id)
)
First two tables where the same, but it generated the employee table this way:
CREATE TABLE employee (
id bigint NOT NULL,
name character varying(255),
role_id bigint,
CONSTRAINT employee_pkey PRIMARY KEY (id ),
CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id),
CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES bookkeepingparent (id)
)
You can notice that the fk_employee_role_id references the bookkeepingparent table, instead of the role table. I have a large heirarchy of JPA entities, and I want the bookkeepingparent to be the superclass of most of them. This is primarily because of some very specific Id generation strategies and other bookkeeping activities. This design, helps keep all this book keeping code separate from the functional code, and let programmers working on the functional code not worry about it.
All this worked alright till the the number of tables grew. Now we see that, for all ManyToOne and OneToOne relationships, JPA is generating foreign keys referring to the parent table. With 200 odd tables, the inserts are already slow because all foreign key constraints refer to the bookekeepingparent, and every entity, when persisted for the first time, inserts into the bookkeeping parent table. Which I guess is checking some 150 odd constraints.
So, following are my questions: why is JPA doing it? Is it a standard JPA behaviour? (I'm using EclipseLink) If I manually change the DB schema, are their any pitfalls to expect?
This is my first question on StackOverflow, I tried my best to search for any existing answers. Apologies if I missed any. Thanks.
You are using joined inheritance, which means that for every class, the bookkeepingparenttable is the main table and any subclass table is secondary. The primary key for the subclasses are inherited from the parent, and foreign keys must reference the id, so the will all reference the id in bookkeepingparenttable by design. Different providers allow referencing non-pk fields, but it can cause problems as resolving references can require database hits instead of using the cache.
The database constraints are not JPA related, so you can change them as required and not affect the app as long as inserts updates and deletes will still conform.

JPA 2 #JoinTable with keygeneration

Is there a way in JPA 2 to use a #JoinTable to generate a UUID key for the id of the row? I do not want to create new entity for this table (even if that would solve the problem) and I do not want to create it from the DB.
#ManyToMany
#JoinTable(name="Exams_Questions", schema="relation",
joinColumns = #JoinColumn(name="examId", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="questionId", referencedColumnName = "id"))
private List<Question> questions = new ArrayList<Question>();
db table
CREATE TABLE [relation].[Exams_Questions](
[id] [uniqueidentifier] PRIMARY KEY NOT NULL,
[examId] [uniqueidentifier] NOT NULL,
[questionId] [uniqueidentifier] NOT NULL,
Not sure exactly what the question is, but let me try a response.
For your first sentence alone, I would say "Yes" and "Possibly":
You'll need a separate #Entity class for the Question, and in that class you'd specify the mapping for id.
There is no way using spec JPA to specify auto-generation of a UUID value for a column. There are ways using OpenJPA and Hibernate. EclipseLink will allow you to create a custom generator for this purpose, and their example is, in fact, for a UUID.
If you'd like to expose properties of the join-table OR otherwise have JPA manage them (i.e. the id on the Exams_Questions table), then see this external link (found on this answer). You'll end up with #OneToMany relations from Exam/Question entities to the join table, and #ManyToOne relations from the join table to Exam/Question entities.
Exposing the join table as an entity will let you manage a separate key (uuid). If you don't need the uuid primary key, then don't do this - it's not necessary to solve the problem, as the examId/questionId combination is unique.