I have a OneToMany relation from A to B (A references a list Bs).
When I delete a B using either entityManager.remove(b) or a.getBs().remove(b)or both, and load A again : the deleted B will still appear in the list THOUGH it has been effectively removed from the database! I tried with and without Cascade.ALL on the relation with no success..
Thanks for your help.
You need to do both (unless you use delete orphans). If you do both it should be gone. Ensure you remove it from the correct managed a, not a detached a. Ensure the a actually contains the b to begin with.
You could always call refresh() to confirm that the database state was correct.
Related
We use Eclipselink-2.6 with wildfly-8 server in a JavaEE7 application.
we have three JPA entities A, B, and C.
B and C extend A.
In order to change the type of an object "myObjectId" A to B, we try to:
1- Change the dtype value from "a" to "b" in Table "A" for the instance "myObjectId" using the criteria query.
2- Create a new row in the table "B" in the database for the same id "myObjectId" also with a criteria query.
3- Clearing the cache by evictAll as well Entitymanger using clear functions.
After, when I tried to find all data of type B, the object "myObjectId" came in the list but with type A!
After restarting wildfly server and call findAll, therefore, the data came with type B!
why myObjectId didn't change its type even if the first and the second level cache was cleared!?
See https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching
Essentially EclipseLink maps the JPA cache eviction call to its own invalidation logic, which seems to be keeping a reference to the object using a soft reference so that object identity is maintained. This prevents A1->B1->A1' from happening on cycles with lazy relationships.
Try calling ((JpaEntityManager)em.getDelegate()).getServerSession().getIdentityMapAccessor().initializeAllIdentityMaps() as suggested in the doc and then reading in the changed class.
I am having a problem when updating/merging an entity A which has a reference to another entity B. A also has a reference to an entity C.
I create a new instance of the entity A from a domain object. Also from this domain object I use the ids to get B and C by using entityManager.getReference(<class>, <id>). I call entityManager.merge and entityManager.flush(). So far all is good, the values of both B and C are present in A. When I after the flush do a entityManager.refresh(A), the B is cleared(null), but the C is still there.
I run sql queries to verify that the value is there before the update. After the flush the FK to B is cleared, so when the refresh is called it discovers this.
I do not know what to look for here. Might it be something with how my entities are defined? Persistence-xml? Any tips are much appreciated!
EDIT:
The value of B is only cleared if I do not change the reference. If I change the reference of B to B', then it is updated correctly
The question did not show the entire context of where I was experiencing the problem. The entity A which had a reference to B, also had the foreign key field in it. This foreign key field was always null, so setting the entity reference had no effect.
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;
I have the following entity tree:
ParameterDefinition-->ParameterOperation
ParameterDefinition-->ParameterGroup-->Parameter
Also there is a many to many relationship (mapped to a FK-FK table) between ParameterOperation and Parameter.
All associations are declared as Delete cascade (only the many to many is not Delete cascade).
The thing is that when I MarkAsDeleted Parameter Object through ParameterOperation
(ParameterDefinition.ParameterOperations[0].Parameters[0].MarkAsDeleted) it is deleted from DB and the map table is updated as well (row is deleted), but when I try to delete Parameter From ParameterGroup
(ParameterDefinition.ParameterGroups[0].Parameters[0].MarkAsDeleted) it is not deleted at all (no delete query is executed on DB).
What might be the problem?
Also how do i delete a many to many relationship? for example I want to keep all Parameters and all ParameterOperations but I want to delete the relationship between Parameters[0] and ParameterOperations[0].
How can I do it?
if I set the NavigationProperty - ParameterDefinition.ParameterOperations[0].Parameters.MarkAsDeleted it actually deleted the Parameter from DB what I don't want
Simply removing the Parameter Entity from the ParameterOperation's collection, and then saving your context should be enough to delete the many to many relationship that exists in the junction table.
ParameterDefinition.ParameterOperations[0].Parameters.Remove(ParameterDefinition.ParameterOperations[0].Parameters[0]);
Context.SaveChanges();
What is the right way to delete all of the collection items of an EF entity? In the code below, DocumentItems is the collection of related document items for a document. This code proceedes on Clear() but fails on SaveChanges() because related items are connected to their document via FK and FK is mandatory. So I guess they somehow remain floating up in the air without a foreign key after Clear().
Do I solve this with a foreach loop over the collection calling Remove() on each item or is there another way?
// remove existing document items to prepare for refreshing them
existing.DocumentItems.Clear();
// adds new Document Items
PrepareInvoice(existing, collection);
_repository.SaveChanges();
This is one way of deleting the items in the collection.
VB
TEntityCollection.ToList().ForEach(Sub(o) ctx.DeleteObject(o))
C#
TEntityCollection.ToList().ForEach(x => ctx.DeleteObject(x))
Then you need to call
ctx.SaveChanges()
Clear just removes the reference but doesn't delete the entity.
In your situation
existing.DocumentItems.Clear();
All DocumentItems in the EntitySet will get cleared but you will have to Remove/Delete the actual DocumentItem or the commit with fail, just the same as it would if you tried to delete it in the database.
You need to loop through detach any references, and then delete the entity you wish to remove (unless its nullable and in your situation, it is not)
Alternatively, I have seen implementations that use clear, and an AssociationChangedHandler to automatically delete the old object. Basically, if the change is a "delete/remove" it calls DeleteObject() on the orphaned object.
Trick: When setting up the relationship between Parent and Child, you'll HAVE TO create a "composite" key on the child. This way, when you tell the Parent to delete 1 or all of its children, the related records will actually be deleted from the database.
To configure composite key using Fluent API:
modelBuilder.Entity<Child>.HasKey(t => new { t.ParentId, t.ChildId });
Then, to delete the related children:
var parent = _context.Parents.SingleOrDefault(p => p.ParentId == parentId);
var childToRemove = parent.Children.First(); // Change the logic
parent.Children.Remove(childToRemove);
// or, you can delete all children
// parent.Children.Clear();
_context.SaveChanges();
Done!
Yeah, a year old, but on a minor note... since DeleteObject takes one parameter, which is the same type as the argument for the lambda expression, you can just use:
entityCollection.ToList().ForEach(ctx.DeleteObject);
I am not sure if VB supports a similar syntax, though. Anyone?
Just to answer to Nix comment to the answer,
it seems to me that the EntityCollection.Remove() method only marks for deletion the relationships and not the entities, just as the EntityCollection.Clear() method does.
I know that documentation says that also the entity will be marked for deletion but in my test I've got the behavior I described (anyone can explain me why?).
So, if you have a one to many foreign key constraint in your conceptual model, you cannot save the changes to the context in the persistence store.
The only way I found (since I don't want to CascadeDelete) is looping through the children and invoke context.DeleteObject on each of them, thus removing the entity and the associated relationship.