Spring JPA save update in certain order - spring-data-jpa

Code snippet in my spring service
to update the existing record
//Credit Cards
find.getCreditCards().forEach(creditCard -> {
creditCard.setActiveVersion(false);
businessPartnerCreditCardRepository.save(creditCard);
});
And then insert new 1
//Credit Cards
businessPartner.getCreditCards().forEach(creditCard -> {
creditCard.setVersion(find.getVersion() + 1);
creditCard.setActiveVersion(true);
businessPartnerCreditCardRepository.save(creditCard);
});
The issue is that , Spring JPA first run the INSERT statement and then UPDATE, instead of first run the UPDATE then INSERT.
why I need certain order from UPDATE to INSERT
There is a DB constraint that only 1 record is active at a time. so, when JPA insert without update .. DB shout and kickback to ..... :D
Any Update ?

Do a flush after the update.
You can use saveAndFlush from the JpaRepository or write a custom method in your repository where get the EntityManager injected and perform the flush on it.
Another option would be to make the constraint a deferred constraint so it is only checked at the end of the transaction.

Related

How to return primary key of updated records when using #Query in JPA with Spring Boot

I would like to know whether it is possible to return the primary keys of the records updated by an update query using #Query annotation with Spring boot and JPA
Not by the same repository method that performs the update. It only returns void or the number of updated records.
You could create another query method, with the same where conditions as your update query, which returns only the id attribute. Then you only have to call it just before calling the update query.

EntityState in update?

What is the correct approach while updating a record in CFE ?
We are using webapi controllers, based on this link, the client-side is developped thanks to AngularJS.
I am having troubles updating a record that already exists and my code fails with an CodeFluentDuplicateException.
I read here that EntityState shouldn't be changed manually. When I want to update a server version with the client changes, shall I consider:
Taking the server version and then applying changes made by client ?
Ask the client version to Save() ?
Any other approach ?
Thanks for your answer,
CodeFluentDuplicateException means that you are inserting a record that already exists in the database. This occurs when the stored procedure executes an INSERT statement instead of an UPDATE.
CodeFluent Entities don't use the EntityState to choose whether the entity must be created or updated in the database. Depending on your model, it uses the RowVersion property (insert if null; update otherwise). If there are no way to choose, the stored procedure executes an UPDATE and when no rows are updated it inserts the row. For instance:
CREATE PROCEDURE [dbo].[Role_Save]
(
#Role_Id [uniqueidentifier],
#Role_Name [nvarchar] (256),
)
AS
SET NOCOUNT ON
IF(#_rowVersion IS NOT NULL)
BEGIN
UPDATE [Role] SET
[Role].[Role_Name] = #Role_Name
WHERE (([Role].[Role_Id] = #Role_Id) AND ([Role].[_rowVersion] = #_rowVersion))
END
ELSE
BEGIN
INSERT INTO [Role] (
[Role].[Role_Id],
[Role].[Role_Name])
VALUES (
#Role_Id,
#Role_Name)
END
So in your case I would check the code of the generated stored procedure to understand why it tries to insert the record instead of updating it.
In fact you can change the EntityState manually if you need to, but there are only a few reasons to do it.

How do I delete all data in the Seed method?

I'm using Entity Framework code first with migrations and I want to delete all data in the Seed method, from all tables, except from the __MigrationHistory table. Right after my database is clean, I'll proceed with the seed method, but just adding new objects.
I want this because I develop using a development database and I constantly want to reset it to a default state.
So, what's the best way to delete all data, from all tables, except for __MigrationHistory, in the seed method?
public override void Seed(YourNamespace.Model.DbContext context)
{
// Deletes all data, from all tables, except for __MigrationHistory
context.Database.ExecuteSqlCommand("sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'");
context.Database.ExecuteSqlCommand("sp_MSForEachTable 'IF OBJECT_ID(''?'') NOT IN (ISNULL(OBJECT_ID(''[dbo].[__MigrationHistory]''),0)) DELETE FROM ?'");
context.Database.ExecuteSqlCommand("EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'");
// proceed with the seed here
}

Insert after delete same transaction in Spring Data JPA

Using Spring Data JPA I have the next flow inside the same transaction (REQUIRES_NEW) :
Remove a set of user's predictions with this Spring Data JPA repository method.
#Query(value = "DELETE FROM TRespuestaUsuarioPrediccion resp WHERE resp.idEvento.id = :eventId AND resp.idUsuario.id = :userId")
#Modifying
void deleteUserPredictions(#Param("userId") int userId, #Param("eventId") int eventId);
Insert the new user's predictions and save the master object (event).
eventRepository.save(event);
When this service finishes, the commit is made by AOP but only works in first attemp...not in the next ones...
How can I manage this situation without iterating over event's predictions entries and updating each one inside?
UPDATE
I tried with that and it doesn't work (the adapter inserts the objects I remove before):
#Transactional(propagation=Propagation.REQUIRES_NEW, rollbackFor=PlayTheGuruException.class)
private void updateUserPredictions(final TUsuario user, final TEvento event, final SubmitParticipationRequestDTO eventParticipationRequestDTO)
{
eventRepository.deleteUserPredictions(user.getId(), event.getId());
EventAdapter.predictionParticipationDto2Model(user, event, eventParticipationRequestDTO);
eventRepository.save(event);
}
Hibernate changed order of the commands. It works in below order :
Execute all SQL and second-level cache updates, in a special order so that foreign-key constraints cannot be violated:
1. Inserts, in the order they were performed
2. Updates
3. Deletion of collection elements
4. Insertion of collection elements
5. Deletes, in the order they were performed
And that is exactly the case. When flushing, Hibernate executes all inserts before delete statements.
The possible option are :
1. To call entityManager.flush() explicitly just after the delete.
OR
2. Wherever possible update existing rows and from rest create ToBeDeleted List. This will ensure that existing records are updated with new values and completely new records are saved.
PostgreSQL (and maybe other databases as well) have the possibility to defer the constraint until the commit. Meaning that it accepts duplicates in the transaction, but enforces the unique constraint when committing.
ALTER TABLE <table name> ADD CONSTRAINT <constraint name> UNIQUE(<column1>, <column2>, ...) DEFERRABLE INITIALLY DEFERRED;

how to create a EF data model like a sql server view

I need to create a model of union of several sql server tables and i have to get ability of
insert , select , update and delete ...
(id like to use the model as same as any other model)
any suggestions ?
thanks for reading.
Edit: i tried sql server view but got the fallowing error when i want to insert to sql server view:
Msg 4406, Level 16, State 1, Line 1
Update or insert of view or function 'viewName' failed because it contains a derived or constant field.
You need to create database view + stored procedures for insert, update and delete. You will map the view as a new entity and map imported stored procedures to insert, update and delete operations for that entity.
You actually don't need the database view - you can write the query directly to EDMX by using DefiningQuery but it requires manual modification of EDMX. Default EF tools will delete your manual modification once you run Update from database again.
Even with defining query you still need those stored procedures. There is no other way to make entity based on defining query (view is also imported as defining query) updatable.