I've having an issue where CoreData is unable to fulfill a fault on an object. I assume it's because the object has been deleted and now CoreData is trying to access a property in some context and can't fault it in. To resolve this I attempted to call setRelationshipKeyPathsForPrefetching and pass it the relationships that I want to have prefetched.
Example, I have an Entity A, and it has a to-many relationship to Entity B, but at some point while I'm accessing properties on Entity B, Entity B is deleted in another context and now a fault can't be fulfilled.
[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:#"listOfBs", nil]];
I thought that if I did this, it would prefetch Entity B so that I can call its properties safely but this doesn't seem to be the case.
EDIT: I can't seem to find any info about this but it must be a fairly common problem. If some context has a managed object that is deleted in another context, it should have some way to safely figure out that the object no longer exists rather than just crashing
EDIT 2: I don't think CoreData is properly acknowledging my prefetch request. If I call setRelationshipKeyPathsForPrefetching than the objects that are returned should be faulted in yet even in the case where I don't have an error, I can simply print out the object that get returned and see that they are faulted. Does CoreData not prefetch objects in to-many relationships?
EDIT 3: Ok so perhaps the relationships themselves are prefetched but the properties on the prefetched items are not faulted in. So if I have Entity A and I want to prefetch all of the B's associated with A, I use setRelationshipKeyPathsForPrefetching but all of the properties of the B's are not faulted in.
Figured out a solution. Core Data doesn't allow atomic fetches from the database so if something after prefetching the relationships, Core Data would throw an error. Prefetching the relationships does just that, prefetches the relationships. But not the data. The solution was to use a try/catch and refresh the object on an exception.
Related
Previously I had a bug with the fixrelationships function(Breeze: Differences between Entity Framework and NHibernate with many to many) that has been fixed.
Now I face another problem linked to the fix.
I have an entity Request with a many to many relationship called RequestContact. The many to many is exposed as a many to one on both Request and Contact entities. If I delete a RequestContact from a Request, I got a "null or transient value" error in NHibernate.
What's happening: breeze send my deleted entity over the wire. Once on the server, the relationships of the entity are not loaded (see code line 290) and the delete method crashes since the associations are empty.
The code is similar to my previous post if you want a sample.
Is it a bug? Why associations are not loaded when EntityState is Deleted?
I made a fix in this pull request.
It's a bug, but the fix in the pull request causes errors with one-to-one associations in my tests. It needs some more work.
I have an exception occurring when saving changes to a self tracking entity:
AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
I believe the problem is addressed in other questions such as: Self Tracking Entities - AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager
My question is what is the best way to debug this problem both in development and production. Is there any further information that can be caught/accessed which will detail which entities or the entity types which are causing the exception.
If not will I have to write something to traverse the object graph looking for duplicate keys referencing different objects? If so does anyone have experience of this?
Further info:
My scenario involves the following - the client retrieves an entity via a WCF service which contains collections of further entities all with various FKs to other entities. These FK relationships are all included in the linq query so we have a complete object graph.
The views in the client use previously fetched entities for static data such as lookup tables for performance. If we have say a Customer object with a FK to User this will be loaded when retrieved from the service. If we now add another entity to the object graph e.g. Order and set a User property on this object which has the same Id as in the Customer object but the entity was retrieved at a different point and therefore using a different ObjectContext (i.e. the objects have the same Id but are not the same instance of the object) I get this error.
The link to the other question demonstrates ways to avoid this but I am looking to find more information about which entities are causing the problem so I can track down the error.
This usually happens if you try to AcceptChanges on the context which was used to load entities before - use new empty context for accepting changes. AcceptChanges cannot be used when any entity from STE is already loaded in the context - that is limitation of current STE implementation (but it can probably be removed if you rewrite the template).
As I know there are no detailed exceptions for this kind of problems. For debugging STEs check their generated code. You have whole STE code available so you can browse change tracker and search for entities but it will not be easy.
I'm actually not sure if it is even possible to define duplicates on the client but let's suppose that it is. If you have the control over client code the best way is diagnose the client code. Add some logging and find the reason for duplications. Then remove the duplication because fixing the issue on the client will be easier then fixing the issue on the service. If you don't have control over the client I would say that it is a problem of incorrect data passed to your client and let client's developers to fix it.
I had been banging my head against this problem for more hours than I cared to admit. Finally found that the cause of the problem was that I had listened to the ReSharper hint to make my
context provider static. since that occurred with a variety of other changes, I didn't think to check it as being the culprit. But in my case, that was the issue.
I'm having trouble defining what my OperationContract should be when adding / updating an entity. I want to send an entity (or list of entities) to the ObjectContext via the WCF Service (which will instantiate a Business Manager for me to do the actual validation).
If the entity passes all of the validation rules (which could very well require querying the database to determine pass/fail for more complex business rules), it'll be saved to the database, and I'll need to be able to pass back its ID (Identity Column primary key) and the value of the concurrency token (timestamp column), but if it fails, obviously we want to have a message or messages saying what was wrong. In the case of an update, all we would need would be the new value of a concurrency token, but again we'd want the validation message(s).
To make it trickier, an entity could have multiple child/grandchild entities as well. For instance, a Trip will have Stops, which could potentially have Orders.
I'm just wondering how people handle this in the real world. The simplest examples just show the WCF service's operations like:
[OperationContract]
bool AddEntity(Entity e);
[OperationContract]
bool UpdateEntity(Entity e);
Does anyone have any great ideas for handling this? I guess I'm really just looking for practical advice here.
Should we be trying to save a collection of objects in one service call?
Should we be conveying the validation messages through a fault contract?
Any advice/input would be helpful, thanks!
Should we be trying to save a
collection of objects in one service
call?
If you mean saving whole object graph in one call then the answer is definitely yes. If you mean saving multiple independent object graphs (collection) in one call then the answer is probably yes. It is good idea to reduce number of roundtrips between client and service to minimum but in the same time doing this can introduce complications. You must decide if the whole collection must be saved as atomic operation or if you are happy with saving only part of the collection and returning errors for the rest. This will influence the rest of your architecture.
Should we be conveying the validation
messages through a fault contract?
Yes but only if you will use save operation as atomic because fault contract is exception and exception should break your current operation and return only validation errors. It should be enough to have single fault contract which will transfer all validation errors. Don't fire the exception for each single validation error because it can make your application pretty annoying and useless.
If you want to save only part of the collection which passes validations and return errors for the rest you should not use fault contracts. Instead of fault contracts you should have some container data contract used for response which will carry both ids and timestamps for saved data and ids and errors for unsaved data.
One little note to STEs: Passing back just Ids and timestamps can be probably tricky. I'm not sure if you don't have to turn off tracking when you want to set them and after that turn the tracking on again.
A couple of times on this current project developers have hit the same problem:
An object with related entities, i.e. an Order with a related Customer is sent back via WCF to entitywork to be saved. If the object is new we use AddObject() to put it back in the context and if it has changed, then we use ApplyCurrentValues() to update the object.
The Order object has changed, but the Customer object has not (unless the streaming via WCF affects it in some way). However, when calling SaveChanges() on the context the main object, Order in this example, is saved, but a new copy of Customer is also added to the database.
The workaround that we have found is to set the reference to Customer on Order to null before calling SaveChanges(), however this feels like a bit of a kludge.
What I'm looking for is the "correct" way to solve this problem, something akin to LazySaving = false, i.e. only save the object changed and don't try to create all the related objects.
Thanks in advance for any pointers.
I am not sure about Entity Framework, but I ran into this issue recently with NHibernate. I solved it by implementing save as follows
(1) Retrieve original entity from DB
(2) Update original entity from WCF Data Transfer object using AutoMapper
(3) Save original entity
I am not sure if you are trying to use your entities as DataContracts, in my experience its always better to use Data Transfer Objects rather than entities as you DataContract. If you dont, you continually run into all kinds of trouble, and DTO+AutoMapper gives you the control to solve most issues that you run into
http://automapper.codeplex.com/
We have a project that has two one to many relationships. We encounter a core data fault when we try to delete the parent object. This ONLY happens if the child relationships are empty. So for example:
A project has many to-dos and messages. If we create a project and add a message and a to-do to it, and subsequently call deleteObject on the managedObjectContext we have no problem. BUT if we create a new project and then try to call deleteObject without ever creating any to-do's or messages we run into a relationship fault.
We resolved this by changing the inverse relationship's delete rule from nullify to no-action. This makes sense since this relationship is optional.