I have a main context that I create all my NSManagedObject's on if said object doesn't have any required fields. However, if I want to create an NSManagedObject subclass that does have required fields, I copy the main managed object context and create the object (that has required fields) on this new context. Once all the required fields for the object have been populated, I merge the duplicate context back into the main context. My issue is that all the references I had to the objects with required fields are still on their old context even after the merge? Is there an option somewhere to say "after the merge switch all my object references to their newly-created counterpart in the merged context"? The reason is that after I merge the contexts, I want to start setting them as related objects to each other, but I get an error saying I can't do so with objects that are in separate contexts. The error makes sense, I am just confused as to how I may switch my NSManagedObject subclass's reference to the new one in the main (merged) context.
Related
I've learned that entities are classes that represent the tables inside a database schema. But on this link they speak of an entity being tracked (attached) by the context
http://msdn.microsoft.com/en-us/data/jj592676.aspx
Added: the entity is being tracked by the context...
Do they speak of the objects/instances of entity's (so the classes) getting tracked by Entity Framework? Or literally the entity itself? I'm confused.
In one of my webapplications I am using this code, does it say all instances of FinalStudyDecision are in the modified state, or just the object fsd?
context.FinalStudyDecisions.Attach(fsd);
context.Entry(fsd).State = EntityState.Modified;
Or does this code just do it for one single object?
ObjectStateManager.ChangeObjectState(fsd, EntityState.Modified);
When an entity is attached to a context, the context "knows" the object and starts tracking its changes.
Normally, an entity is attached to a context when it is fetched from the database, e.g. by context.FinalStudyDecisions.Single(x => x.Id == 1) (if there is an item with Id == 1 of course).
But if you've got an existing FinalStudyDecisions that is not known by a context you can use the Attach method to make it known. This usually happens when an object is serialized to and subsequently deserialized from a web client.
If you attach an object to a context its state (EntityState) is Unchanged, so often you will change its state to Modified when you receive it back from a web client. This will trigger EF to store the object when SaveChanges is called.
Both
// DbContext API
context.Entry(fsd).State = EntityState.Modified;
and
// ObjectContext API
ObjectStateManager.ChangeObjectState(fsd, EntityState.Modified);
only change the state of the fsd object.
Important: if you Add an object to a context, either by setting its state Added or by adding it to a DbSet (or ObjectSet), not only fsd but also all its child objects are changed to Added.
This question covncerns my lack of understanding of how to use the core data undo manager and how to restore a NSManagedObject to its state before editing was done.
I am just learning my way around Core Data. I have my NSManagedObject classes set up with their dynamic accessors. I perform a fetch that returns several NSManagedObject entity results. Content from each of these entity results (first name, last name) get put into a table view, and then the user picks one out of the table for detailed view and then editing.
The detail view controller receives a pointer to the selected NSManagedObject entity. As the user edits the fields, the corresponding property value in the NSManagedObject entity is updated. This seemed like the cleanest way to manage these changes.
Now, rather than committing the changes using save, I want to provide a cancel-editing feature that rolls back to what is in the data base for that entity. I really only want to restore the one entity and not perform the entire refetch.
I tried rollback and I tried NSUndoManager (with beginUndoGrouping and endUndoGrouping), and that is not working. I don't think I understand what rollback is really supposed to do.
But in any case, I still want to restore the property values in just that single entity (taking the lazy approach to only fetch what is needed, which is the one entity) so that my detail view controller can refill its view with the correct information. Right now it is using the NSManagedObject entity values, which contain the edited values, which were cancelled.
I suppose I could just start the edit process by creating a copy of the NSManagedObject. If the cancel-editing button is pressed, I could copy it back into the original. (I might even be able to just replace the original with the copy by moving the pointer. But since the pointer has actually been passed through several objects, I'm not sure how to manage the retain number on the copy.)
Does anyone have any other suggestions?
Thanks
Using rollback should accomplish what you want and I'm not sure what it doesn't. It is probably an implementation detail error.
You can find the specific managed object/s that were updated but not yet saved by calling the context's updatedObjects.
In a subclass of NSManagedObject my overridden implementation of willTurnIntoFault is being called twice when undoing some code which originally created the object in question. This results in a crash when attempting to double-unregister for KVO on a key path.
The Apple documents say this is the right place to un-register for KVO.
A bit of context - the undo operation involves removing the corresponding view of the model from it's superview. The view retains it's model.
So my question is: what kind of programmer errors can result in willTurnIntoFault being called twice in a subclass of NSManagedObject?
Note: Previously I was overriding dealloc in this class but have since realised this is not recommended for subclasses of NSManagedObject. I've since moved this code into -didTurnIntoFault. I'm not currently overriding any other methods which the Apple docs say you should not override.
For posterity's sake: I had the same problem. In my case I had an object A with a (to-one) relation to an object B. When A got deleted B's inverse relation to A was set to null. This caused B's observeValueOfKeyPath:ofObject:change:context method to be invoked (where keypath was B's relation to A). Unfortunately this method checked a property of A, causing the faulting of A to be cancelled (note that in this situation awakeFromFetch does not get called--I presume because the object never actually did get to fault state). Hence I might might get a second call to willTurnIntoFault later and the object would try to unregister for KVO again, resulting in a crash--just like in the OP.
For me the solution was to change the delete rule for A to cascade, so that the B object got deleted when the A object got deleted AND to unregister for KVO in prepareForDeletion. This is important because the deletion of A will still cause B's inverse relation to be set to nil before B is actually deleted.
Note that prepareForDeletion gets called before but not instead of willTurnIntoFault. Hence, if you unregister for KVO in both, you need to maintain some state to make sure you have not already unregistered.
Seems the issue was caused by a custom setter method which was setting/unsetting KVO values from within willTurnIntoFault.
I'm designing my first project using Core Data (for iPhone) and Im having some issues that might be related with my design approach.
I'm doing an application that allows the user to create an Order (let's say for a restaurant).
I'm using the graphic designer to model my persistence object (i.e. OrdeMO). I add MO to the ead of each name to indicate its a Managed Object.
I use XCode to create the Managed Object Class automatically.
I have created some "DAO" classes that allows you to search or create a new object in the Managed Context.
Now to my problem.
I want to create an OrderMO object to store the order the user is creating, BUT I don't want it to be part of the context until the user actually places it.
I tried creating the object with [OrderMO alloc] but the object I get is "incomplete" and when I try to set any of its attribute I get an error.
I'm assuming the problem is that I need to create the order IN the context in order to use it. Is that so?
I have considered various options:
Create the object in the context and the user rollback if the user discards the order. The problem is that the user might save other context object during the process (like his prefs) so this doesn't work. Is there a way to create the object "inside a separate transaction" of sorts?
Create a wrapper object that will hold the same data as the MO, and then only create the MO when the user place the order. The downside of this is that I have to maintain a new class.
Create an attribute in the MO, such as "placed", and use to filter my searches in the context. The problem with this one is that I will end up with "trash" objects in the domain (i.e. unplaced orders) and I will have to do some cleanup from time to time...
Do I have any other choice?
Any suggestion is appreciated.
Thanks (for reading this long post!)
Gonso
You should create the OrderMO object in the managed object context and then delete it if the user decides not to place the order.
If the context is saved before the object is deleted, the "trash" object will be deleted from the persistent store on the next save (if the context wasn't saved, the "trash" object will never be saved to the persistent store).
The flag to determine if the order was placed or not does not have to live in the OrderMO object as you suggest in option 3. It could be in the view controller that is tracking the order(s) that are being edited. And, again, you won't have "trash" objects because they will have been deleted.
I want to follow the DDD philosophy and not access entity objects of an aggregate directly. So, i have to call the root object to get the associated entity. But In other cases I dont always want every associated entity to load when the root is called. Is that the purpose of lazy loading?
How do I access entity objects through the root without loading all the associated objects everytime if i disable lazyloading feature of linq?
EDIT:
For example, If I have a Person as the Root Entity, and the Person has Name, Addresses and OwnedProperties. If I want to get a list of People so that I could display their names, I dont necvessarily want to load up Owned Properties every time on the call to the Repository. Conversely, on another page I may want to show a list of OwnedProperties, but do not want the other information to load with the call. what is the simple way of just calling the Person without the owned property entity other than creating a new person object without that owned properties?
I don't thinks that's possible without lazy loading.
Getting all data at once: Eager Loading
Getting data when accessed: Lazy Loading
According to your edit:
What I do in these situations, is create a 'View' class or a 'DTO' class which just contains the properties that I'm interested in.
For instance, I could have a 'PersonView' class which just has a Name property for instance.
Then, using my OR/M mapper (I use NHibernate), I create a HQL query (or Criteria query) which works on my 'Person' entity. Before I execute the query, I tell NHibernate that I want 'PersonView' objects as a result (I specify a projection). Then, NHibernate is smart enough to execute a query that only retrieves the columns that are necessary to populate the PersonView instances.
One way to avoid lazy loading is just using the object 'id'