Transaction silently rolled back because it has been marked as rollback-only when trying to update an object with PUT API - jpa

API used to update the object: PUT
Functionality: Add new object if not exist in db or update on existing object along with child class (one to one or one to many mapping were there)
During doing update with full object below steps I am performing,
Optional<OcpiCustomer> customer = ocpiCustomerRepository.findById(cust.getId());
Optional<OcpiLocations> existingLocation = ocpiLocationsRepository.findByLocationIDAndOcpiCustomerId(locationId, cust.getId());
OcpiLocations location = ocpiLocationsMapper.toEntity(ocpiLocationDTO);
location.setOcpiCustomer(customer.get());
logger.info("existing PUT location? "+ existingLocation.isPresent());
if(existingLocation.isPresent()) {
location.setId(existingLocation.get().getId());
}
location = ocpiLocationsRepository.save(location);
So first I am fetching existinglocation if exist then new location object will be updated with seeing if of existing object. But doing so the side object with OneToOne mapping is getting generated as new instance (the older one remain as it is) which I am looking for a solution.
When I test to update same object with PUT its getting updated and also created additional entry in child object and then during GET of same object it throw error,
Error:
Caused by: org.hibernate.HibernateException: More than one row with the given identifier was found: 15, for class: so.so...
Transaction silently rolled back because it has been marked as rollback-only in response

Related

"Cannot insert explicit value for identity column in table 'x' when IDENTITY_INSERT is set to OFF" - inserting record with nested custom object

I get the error "Cannot insert explicit value for identity column in table 'UserPermission' when IDENTITY_INSERT is set to OFF" trying to insert a record as follows:
dbContext.User.Add(someUser);
dbContext.SaveChanges();
That being said, the User file has the custom class UserPermission as one of its parameters, and someUser's UserPermission is not null and has a set ID parameter. Why does this happen and is it possible to avoid getting this error without having to explicitly add a UserPermissionID foreign key parameter in my User model and setting the UserPermission parameter to null?
Thanks in advance.
This issue typically happens when deserializing entities that have related entities in the object graph then attempting to add them. UserPermission is likely an existing record that in the DB is set up with an identity PK, but EF doesn't appear to recognize that in the entity definition. (I.e. set to DatabaseGenerated(DatabaseGeneratedOption.Identity). If it had been you would most likely be seeing a different problem where a completely new duplicate UserPermission was being created.
If someUser, and it's associated someUser.UserPermission are deserialized entities then you need to do a bit of work to ensure EF is aware that UserPermission is an existing row:
void AddUser(User someUser)
{
var existingPermission = _context.UserPermissions.Local
.SingleOrDefault(x => x.UserPermissionId == someUser.UserPermission.UserPermissionId);
if (existingPermission != null)
someUser.UserPermission = existingPermission;
else
_context.Attach(someUser.UserPermission);
_context.Users.Add(someUser);
_context.SaveChanges();
}
In a nutshell, when working with detached entities that a DbContext may not be tracking, we need to check the Local state for any existing tracked instance for that ID. If we find one, we substitute the detached reference for the tracked one. If we don't find one, we attach the detached one before Adding our user.
This still isn't entirely safe because it assumes that the referenced UserPermission will exist in the database. If for any reason a non-existent UserPermission is sent in (row deleted, or fake data) you will get an exception on Save.
Passing detached entity references around can seem like a simple option at first, but you need to do this for every reference within a detached entity. If you simply call Attach without first checking, it will likely work until you come across a scenario where at runtime it doesn't work because the context happens to already be tracking an instance.

Entity Framework - Last ID of Entree

Currently I am programming an application which saves and deletes entries in a database (code first with entity framework). My question is how can I get the next database id (configured with auto increment - so it added automatically +1).
I tried something like:
var a = databaseContext.MyObject.LastOrDefault().Id;
var myNextDatabaseId = a+1;
This pseudo code is working for most of the cases. But if i had 5 entrees in my database and delete all the five entree's my next database-counter would be 6. When i'm using the code above it will return "null" becouse there is really no entree. But i must get the next database auto increment id.
Is there a possibility which doesn't create a new database entry? Think this shouldn't be necessary.
For example following data construct:
Inserted entry one (internal id = 1)
Inserted entry two (internal id = 2)
Delete entry one
Delete entry two
Read last database entry (entry = null). All data was deleted but I am trying to receive the next auto-increment id 3
Use an explicit transaction scope and identity column. Trying to maintain IDs at the application level isn't scale-able and will be prone to concurrency errors.
Ideally the transaction should span the web service call to roll back automatically if the call fails. With an explicit transaction you can call your context.SaveChanges() which will expose the next ID assigned to the entity, and then roll back if the web service call fails. This can be a transaction managed by the context or TransactionScope.
see: https://msdn.microsoft.com/en-us/library/dn456843(v=vs.113).aspx

Get entity JPA Id after merge?

I have a freshly created entity (detached because not yet saved in the DB). This entity holds another entity that already exists in the db (but is detached, too). Thus, I would use em.merge(myNewEntity) to store it.
If I want to get the new created ID, I would use em.flush() afterwards. Then I invoke myNewEntity.getId(). With persist I receive an ID generted by the DB/JPA. With merge, it does not. The ID in the object remains null. Why is that?
The result of the merge operation is not the same as with the persist operation - the entity passed to merge does not become managed. Rather, a managed copy of the entity is created and returned. This is why the original new entity will not get an id. So instead of
em.merge(newEntity);
Long id = newEntity.getId();
it should be
managedEntity = em.merge(newEntity);
Long id = managedEntity.getId();

Store update insert or delete statement affected an unexpected number of rows (0)

I'm using the code show below to update an entity model. But I get this error:
Store update, insert, or delete statement affected an unexpected number of rows (0)
And reason of this error is also known, it's because the property does not exist in the database. For that I found have only one option: first check that the entity exists, then update it.
But, as I'm updating 10,000+ rows at a time, it will be time consuming to check each time in database if this property exist or not.
Is there any another way to solve this ?
Thank you.
foreach (Property item in listProperties)
{
db.Properties.Attach(item);
db.Entry(item).Property(x => x.pState).IsModified = true;
}
db.SaveChanges();
You use it the wrong way. If you want to update without retrieving the entity, just change the state of the updated entity with providing the id.
foreach (Property item in listProperties)
{
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
Attaching an existing but modified entity to the context
If you have an entity that you know already exists in the database but
to which changes may have been made then you can tell the context to
attach the entity and set its state to Modified.
When you change the state to Modified all the properties of the entity
will be marked as modified and all the property values will be sent to
the database when SaveChanges is called.
Source
I got this error Just by updating EF version from 5 to 6 solved the issue.

entity framework update foreign key throws exception if AutoDetectChangesEnabled set false

I have table A and B
A like : id
name
bid
B like : id
type
in table A has a data record reference with B1,now I want update A reference with B2.
in my unitofwork if I set AutoDetectChangesEnabled = true it's work ok, but I set AutoDetectChangesEnabled = false reason is I want to up speed throw the exception like this:
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property value(s) of 'GoodsKind.goods_kind_id' on one end of a relationship do not match the property value(s) of 'EnrolmentType.goods_kind' on the other end."
how cand i do?
I just had this error as well. The problem for me was that I have a complex type. When I changed the master record (let's say Person) I also wanted to change the complex type List with his contact information(s). So when I tried to save them both in one screen I got this error. Check if you fill all the ids on your screen for the master record and the complex type records. Check if they are posted to the server (if you use in example MVC). You can do this by checking the Bind statement by your MVC action.
The error says that the ID and the object specified doesn't match. This means that you are saying that A has a B with ID=2 but at the same time you have A with an object of type B with ID=5. Because you are working in a disconnected environment, EF doesn't know which one is the correct. To solve this issue you can do one of the following things:
-Get the object from EF, modify it and then save (connected environment).
OR
-Update the IDs manually (update A setting ID=5 because the object B has ID=5).
Always remember that EF tracks changes if it is in a connected environment and the tracking is enabled. If not, it has no clue of the changes you made until it tries to save it in the DB (where the object is compared with the values in the DB). One thing that you can do to manually tell EF that the entity has been modified in a disconnected environment is:
dbContext.Entry(objectA).State = EntityState.Modified;