Spring Data JPA : not persisting parent relation column mapping - spring

Currently I am following this URL & implemented the similar kind of code at my end.
But it gives an error at my end something likewise,
null value in column "file_id" violates not-null constraint
Here, category_id is one of my parent_entities primary key.
Following lines where parent entity I am passing properly & checked through Debug,
EntityManager entityManager = BeanUtil.getBean(EntityManager.class);
entityManager.persist(new FileHistory(target, action));
UPDATE -
Here, instead of the following config,
#ManyToOne
#JoinColumn(name = "file_id", foreignKey = #ForeignKey(name = "FK_file_history_file"))
I've used,
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "file_id")
Also, I used #PostPersist instead of #PrePersist these are the changes only I did against this article.

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/JPA twice uniderectional not working, because of #JoinColumn(nullable = false)

I have problem with unidirectional mapping and need help.
I have 2 Entities with the same unidirectional mapping.
The first one:
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "massnahme_id", nullable = false)
private Set<VerortungDAO> verortungen = new LinkedHashSet<>();
The second one:
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "massnahmen_verbund_id", nullable = false)
private Set<VerortungDAO> verortungen = new LinkedHashSet<>();
If I try to save one Entity, hibernate throws an Exception because of the second Entity definition (not null).
org.hibernate.PropertyValueException: not-null property references a
null or transient value
If I change the JoinColumn to nullable = true, then the unidirectional mapping not working and the list is not saved in DB.
What can I do to make it work?
Make the associations bidirectional and map the to-one association in VerortungDAO, or if you don't want that, at least map the FK-columns. If you map it bidirectional, use #OneToMany(mappedBy = "..."). Either way, you will have to initialize the two to-one associations or FK-columns on the VerortungDAO objects.
PS: An entity isn't a DAO (data access object), so the naming xxDAO is quite confusing for an entity.

Join query in Spring Data JPA

I have two tables:
Car_company which has the attributes of:
C_id (primary key),
C_name
Car_model which has the attributes of:
Com_id (referenced to C_id of Car_company),
Model_year
Warranty
I wish to access both of these tables individually and also I would like to perform a join operation on them and display all of the car_models along with their car_company name. I tried using both JPQL and native query but nothing worked. I also made sure to use the OneToMany and ManyToOne associations but I ended up getting infinite nesting,i.e, the models have car_company as field, this inturn has car_models as a list, and this keeps going. Please help me with entity classes and DAOs.
You can get a List of CarModel for each car company in the CarCompany entity through the oneToMany annotation like this:
#OneToMany(mappedBy = "carCompany", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<CarModel> carModels;
or get all car models with their company field in the CarModel entity like this:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Com_id", referencedColumnName = "C_id", nullable = false)
private CarCompany carCompany;
Just try to define your relationships as LAZY for performance purpose and to prevent circular nesting when you map your responses to a Data Transfer Object (DTO).

Spring JPA - insert list with batch_size using native query in JpaRepository or CrudRepository

UPDATE: Thank you to #M.Deinum for informing me how to deal with the #ManyToOne cascade issue that I was previously stuck on by using EntityManager getReference or JpaRepository getOne function. I am now able to batch save with basic JpaRepsitorymethods as follows:
#Transactional
public void insertCommands(List<CommandDto> dtos) {
final List<Command> commands = new ArrayList<>();
for (CommandDto dto : dtos) {
ZonedDateTime now = ZonedDateTime.now();
final Request request = requestRepository.getOne(dto.getRequestId());
String commandId = UUID.randomUUID().toString();
final Command command = new Command();
command.setId(commandId);
command.setCreatedBy(SYSTEM);
command.setCreatedTimestamp(now);
command.setStatus(dto.getStatus());
command.setContent(dto.getContent());
command.setSendOnDate(dto.getSendOnDate());
command.setRequest(request);
commands.add(command);
}
commandRepository.saveAll(commands);
}
Original post content as seen below:
I need to insert multiple rows to my application's database using the batch_size property set in my properties:
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_size=10
I am looking for a way to insert them using nativequery in JpaRepository or CrudRepository with a syntax along the lines of the following, but allowing for multiple rows:
#Modifying
#Transactional
#Query(nativeQuery = true, value = "INSERT into command (id, created_by, created_timestamp, " +
" updated_by, updated_timestamp, status, content, send_on_date, request_id) " +
"VALUES (:id, :createdBy, :createdTimestamp, :updatedBy, :updatedTimestamp, " +
" :status, :content, :sendOnDate, :requestId) ")
int batchInsertCommandDto( #Param("commands") List<CommandDto> commandDtos);
How can I perform this sort of query with a list?
NOTE: Before you bring up EntityManger, I must note that have not had any luck with saveall functionality because:
I am translating the data from it's JSON-friendly class (CommandDto) to its data entity class(Command)
The class for the entity (Command) has a #ManyToOne annotation for one or more Object fields whereas the JSON object (CommandDto) simply has the id of these fields. For example, java class for command entity has "request" field:
#ManyToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
#JoinColumn(name = "request_id", foreignKey = #ForeignKey(name="fk_rcommand_request_id"))
private Request request;
Whereas CommandDto object simply has field "requestId". That means that if I simply try creating a request object with only the requestId, entityManager will fail to save because the Request object is not fully formed and therefore not recognized. It would be grossly inefficient to retrieve the Request object for each command being saved, so I am looking to do the mapping as seen in the nativequery above.

Hibernate Annotation Formula NullPointer Exception or invalid identifier errors

I was trying to use #Formula in one of my entity classes.
What I need to do is select a boolean from another entity.
I tried to put the property definition but it keeps throwing a NullPointerException when publishing, I did it as follows
#JoinColumn(name = "SOIR08_FECHA_CARGA", referencedColumnName = "SOIR15_CODI_FECHA", nullable = true)
#ManyToOne(fetch = FetchType.EAGER)
private FechaCarga loadDate;
#JoinColumn(name = "SOIR08_RECEPTOR", referencedColumnName = "SOIR05_CON_DISTRITO_TELEFONICO", nullable = true)
#ManyToOne(optional = true, fetch = FetchType.EAGER)
private DistrictPhone receiver;
#Formula("(select io.done from Table io where io.district = receiver and io.loadDate = loadDate)")
private Boolean isDone;
Then I tried putting the #Formula annotation in the getter
#Formula("(select io.done from Table io where io.district = receiver and io.loadDate = loadDate))")
public Boolean getIsDone() {
return isDone;
}
but when I access the page where the property must be shown I get ORA-00904: "APROB0_"."ISDONE": invalid identifier
Any idea,suggestion or workaround will be highly appreciated.
You have to write pure SQL in the #Formula (but not HQL).
I couldn't find a way to use this annotation without getting errors.
What I decided to do was to add a column in the table, and fill it when a insert was made, not the best way but I needed to do it fast and there was nothing on forums that worked for me.
Thanks.

Resources