how to put entity associations in JSON (inside POST HTTP request) while performing CREATE operation of entity has association of another entity? - spring-boot

I am using Spring Boot as my backend framework and I have a PERSON entity which has a one-to-one relation with GENDER entity.
I am using #RepositoryRestResource for PersonRepository and GenderRepository.
The GENDER table is already filled with two records of MALE and FEMALE and I have an angular form which creates a new PERSON.
In angular form, there is a list of genders with two items gotten from GenderRepository (male/female). how can I put the genderId in JSON of POST Request body to create a new Person.
I see that most of people use text/uri-list to update existing records however I want to set it while creating not updating.

You can do that by giving a link to the gender entity.
Person Entity
#Entity
public class Person {
#Id
#GeneratedValue
private Long id;
#OneToOne
private Gender gender;
//Other columns and getter/setters are removed for brevity
}
Gender Entity
#Entity
public class Gender {
#Id
#GeneratedValue
private Long id;
#Column
private String gender;
}
The following POST request to localhost:8080/api/persons with Content-Type header set to application/json creates a new Person entity and sets it's gender to the Gender with the id of 1.
{
"name": "Mahsum",
"surname": "Demir",
"gender": "http://localhost:8080/api/genders/1"
}

Related

Spring does not persist bi-directional OneToOne relation on owning side

In my spring boot project I have a Document class that has a bi-directional OneToOne relationship to an Invoice class, which share the same ID.
Document
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Invoice invoice;
Invoice
public class Invoice {
#Id
#Column(name = "document_id")
private Long documentId;
#OneToOne(mappedBy = "invoice")
#MapsId
#JoinColumn(name = "document_id")
private Document document;
The document entity is created prior to the invoice entity. Later on I create an invoice entity via a MapStruct DTO-Mapping. I then save the entity to "generate" the document_id value.
After saving the invoice entity, I assign the invoice entity to the document entity and save the document entity via the repository. However, the relation to the invoice entity is not persisted in the database.
The invoice entity persists as should be with the corresponding document_id as primary key.
Service code
Invoice newInvoice = invoiceMapper.fromDto(dto);
newInvoice = invoiceRepository.save(newInvoice);
document.setInvoice(newInvoice);
documentRepository.save(document);
InvoiceMapper
#Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, uses = {DocumentService.class})
public interface InvoiceMapper {
#BeanMapping(ignoreByDefault=true)
#Mapping(source = "document", target = "document")
Invoice fromDto(Dto dto);
Previously, I tried mapping the document_id in the MapStruct mapper aswell, but then I received an "attempted to assign id from null one-to-one property" exception on save (even though document and document_id were correctly defined).
When debuggin the code, it correctly shows that the invoice entity was set on the document entity, but unfortunately it is not persisted in the database.
Curiously, I am almost certain that at some point in the coding process it did work as intended. But I can not figure out where the issue is. Help would be much appreciated.
This is not setup correctly as you have not specified anything to set the Invoice's document_id column - you'd have to set this yourself from the documentId long. You must pick one side to have a foreign key to the other - presumably the Invoice has the foreign key to Document and is going to use that as its primary key as well. If that is the case, this needs to be:
public class Invoice {
#Id
#Column(name = "document_id")
private Long documentId;
#OneToOne //this is the owning side of the relationship!
#MapsId
#JoinColumn(name = "document_id")
private Document document;
..
}
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(mappedBy = "document")
private Invoice invoice;
..
}
MappedBy indicates that the other side controls setting the foreign key values. Note though that your Invoice will not have a documentId value set, and that you do not need to manually set it. The MapsId annotation tells JPA to pull the value from the Document ID when it is generated and to use that for the document_id column, and will set the documentId Long at the same time.
This then will allow you to create a new Document and Invoice and just call save on the document - once. It isn't enough to just add an invoice to the document - the ID within Invoice is entirely controlled by the Invoice.document reference, so if it isn't set, it will be left null. You must maintain both sides of bidirectional relationships yourself to have the model in synch with what you want in the database. Or at least set the owning side of any bidirectional relationship.

Spring Boot: How to create a new entity that references exisiting ones (by Id) [duplicate]

I have been playing around with JPA and came across this scenario and wanted to know how to solve this.
I have 2 tables namely Company and Employee.
So here an employee can work for only 1 company, therefore #OneToOne uni-directional mapping is done in Employee class. And the company details in the Company table would already exist.
So when I try to insert a record into Employee table, I even create a reference to the company, add it to the Employee class and save it using my EmployeeRepository's save method. Since the company_id would already exist in Company table, it should just refer it instead of creating a new company. But this is not happening.
I get an exception saying company object is still in the transient state. I can solve this by adding CascadeType.All but I don't need to insert the company rather I have to just link the company to the employee.
Here are the code snippets.
Employee Class
#Entity
#Table(name = "employee")
#Setter
#Getter
public class Employee
{
#Id
#GeneratedValue
private Long id;
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "employee_name")
private String employee_name;
#OneToOne
#JoinColumn(name = "company_id")
private Company company;
}
Company class
#Entity
#Table(name = "company")
#Setter
#Getter
public class Company
{
#Id
#GeneratedValue
#Column(name = "company_id")
private Long id;
#Column(name = "company_name")
private String companyName;
}
Company Table
company_id company_name
1 Dell
2 Apple
3 Microsoft
Here is how I am creating the Employee object
Employee emp = new Employee();
emp.setEmployeeId(10);
emp.setEmployeeName("Michael");
Company company = new Company();
company.setId(1);
emp.setCompany(company);
employeeRepository.save(emp);
Please, someone, let me know how to link the company class to an employee class rather than saving one more company.
The best solution for me is to lazy load your company with a proxy. To do it with Spring Data JPA, you need to make your company repository extends JpaRepository. That give you access to the method getReferenceById :
Employee emp = new Employee();
emp.setEmployeeId(10);
emp.setEmployeeName("Michael");
emp.setCompany(companyRepository.getReferenceById(1))
employeeRepository.save(emp);
If there is no company for the given id, an EntityNotFoundException is throw.
With a proxy, you avoid the request to the database in most case because Hibernate use its cache for check the existence of the company. But if my memory serves me correctly, Hibernate gonna make a request to the database at each call to a getter of the proxy, except for getId(). So, in your case it's a good solution, but don't use it all the time.
Assuming the Company may have more than one Employee the relation is a ManyToOne, not a OneToOne.
If you want to reference an existing entity, load it instead of creating a new one:
Employee emp = new Employee();
// ...
emp.setCompany(companyRepository.findById(1));
employeeRepository.save(emp);

Save only one field of an entity to another table

How do I only save a certain field/property of an Entity for another entity?
I have a Key entity with id and name properties.
In my Door entity, I would like to accept a Key but only save in the database the id
Is that possible?
Have a look at the #Transient annotation. Example from the docs:
#Entity
public class Employee {
#Id int id;
#Transient User currentUser;
...
}
#Transient will mark the annotated element to not be persisted.

Inject data in json entity with Spring Data REST

I have JPA entity for department:
public class Department {
#Id
#Column(unique = true, nullable = false)
private long id;
#Basic
#Column
#Nationalized
private String name;
#Basic
#Column(length = 400)
#Nationalized
private String branch;
...
}
And REST repository
#RepositoryRestResource(collectionResourceRel = "departments", path = "departments")
public interface DepartmentRestRepository extends PagingAndSortingRepository<Department, Long> {
...
}
Entity's branch field is IDs of entity parent departments separated by space, e.g. 1 2 3.
When I query specific department via /api/departments/ID is it possible to attach to it field like parents with all parent entities queried?
I tryed to add getParents method to entity, but it obviously gave me unneeded parents queries with all entities recursively.
Update 2019.01.17:
As a workaround I splitted Department entity into Department and DepartmentWithParents. I added Department getParents() method to DepartmentWithParents entity and exposed REST API method that returns DepartmentWithParents.
Is there better way?
As a workaround I splitted Department entity into Department and DepartmentWithParents. I added Department getParents() method to DepartmentWithParents entity and exposed REST API method that returns DepartmentWithParents.

How to update a REST Resource with Spring Data Rest that has a OneToMany and nested a ManyToOne relation

I have a simple Invoice System where I need to create and update Invoices. I'm trying to use Spring Data Rest for that, but from what I get from the docs I really would end up doing a lot of calls to implement an update.
#Entity
class Article {
#Id
#GeneratedValue
Long ID;
#Basic
String name;
}
#Entity
class Invoice {
#Id
#GeneratedValue
Long ID;
#Basic
String customer;
#OneToMany(cascade=CascadeType.ALL)
List<InvoiceItem> items;
}
#Entity
class InvoiceItem {
#Id
#GeneratedValue
Long ID;
#Basic
double amount;
#ManyToOne
private Article article;
}
I'm using Spring Data Rest to expose this model to my web fronend via these Spring Data Rest/JPA Repositories
#RepositoryRestResource(collectionResourceRel = "articles", path = "articles")
interface ArticleJPARepository extends JpaRepository<Article, Long> {}
#RepositoryRestResource(collectionResourceRel = "invoices", path = "invoices")
interface InvoiceJPARepository extends JpaRepository<Invoice, Long> {}
#RepositoryRestResource(collectionResourceRel = "invoiceitems", path = "invoiceitems")
interface InvoiceItemJPARepository extends JpaRepository<InvoiceItem, Long> {}
So let's say I have an update form that looks like this:
where I can do several things:
Update Invoice customer
Change an Article of an existing InvoiceItem
Remove some of the InvoiceItems
Append a new InvoiceItem
From what I get from the Spring Rest Docs is that I need to make several calls now.
Update of the invoice customer I need to PUT /invoices/1
then update n the Article and amount in an InvoiceItem PUT n times PUT /invoiceitems/<x>/
Append m new InvoiceItems m times POST /invoiceitems then POST /invoices/1/items
Delete InvoiceItem 2 DELETE /invoiceitems/2 and then DELETE /invoices/1/items/<2>
Is there a simpler way to realise such an update with Spring Data Rest?

Resources