Restoring Core Data Master-Detail selections across runs - core-data

I'm trying to make a row selection in an NSTableView persist across app runs.
I have an NSTableView that acts as a Master view, and an NSCollectionView for the detail view. My sample project is here:
http://www.filesend.net/download.php?f=3f34594d71e32b2c1fbef768eccb56b0
These two views are bound appropriately to NSArrayControllers with Cocoa bindings. These are, in turn, bound to a Master Entity, a Detail Entity and a one-to-many relationship “myChildren” in a CoreData store. The “myDetailAC” Content Set is bound to the CD relationship. In my App Delegate, I create some sample data in the applicationDidFinishLaunching callback.
This all works swimmingly well once the app is up and running… selecting rows of the Table causes the detail NSCollectionView to show the details for the master item. In fact, what I've built serves as a good starting example for Master-Detail setup using Core Data and Cocoa bindings.
The problem is this: when I quit the app and restart it, I would like the TableView row to be selected with the most recent master selection (and automatically the appropriate detail data set).
One of my attributes in my CD Master entity is isSelected, which is set based on which row of the NSTableView was last selected.
I have attempted to override NSArrayController in “MasterAC.m" for the master table. In here, I've attempted to call setSelectionIndexes from within it to alter array controller's selection based on the isSelected flag. I do so from within the array controller's arrangeObjects method.
No dice.
Can anyone help out with persisting the Table Selection across runs of the sample app?
In short, if I quit the app with “Parent #3” selected, then running the app again will cause “parent #3” to be selected along with its detail info.
Some other suggestions on SO deal with this using NSUserDefaults, but not Core Data.
Restoring the selection in an NSTableView (NSWindowRestoration)

What might be the easiest solution, if you’re targeting newer OSes, is just to use "state restoration." It’ll reach into the master table and essentially re-click the selection for you, and it even scrolls to the right point. It’s kind of magical when it works.

Related

Add Select tickbox to PXSelectReadOnly View

Is it possible to add a select tickbox to the PXSelectReadonly View, and make it available for the user to tick items from the grid?
I tried adding it but it is always disabled. I can understand that this is because the PXSelectReadonly does not allow updating so everything would be read-only, but is still a way to achieve this, or do you need to use a standard PXSelect view, and then disable everything except the select tickbox?
Difference between read-only and regular data views is explained in detail in the Merged and Read-Only Retrieval Modes section of the T200 training class, which can be downloaded from Acumatica Open University). Read-only data view types do not contain or execute any UI presentation logic and, in terms of presentation, logic are identical to regular PXSelect types. Have you tried enabling Select field in the RowSelected handler or BLC constructor? It would also help if you update your question with source code of your DAC and BLC.
Update based on the comment from Joseph Caruana below:
Besides the difference in data retrieval modes, PXSelectReadOnly data views now make entire grid read-only ignoring all field state configurations made at the runtime via PXUIFieldAttribute.

Master - Detail Application using Two NSTreeControllers, Core Data and Bindings

I am facing a problem when trying to do a Master-Detail application using Master (NSOutlineView+NSTreeController) and Detail (NSOutlineView+NSTreeController) setup.
Here is a simplest application based on Abstract-Tree example app from Apple.
https://s3.amazonaws.com/applicationtests/AbstractTree-MasterDetail.zip
I have basically a left Project Browser using a Tree Nodes, and Right Detail Browser showing the detail Tree that rely on Project Browser selection.
My setup is trivial.
Master NSOutlineView binds to Master NSTreeController handing a CoreData entity Project Node.
Detail NSOutlineView binds to Detail NSTreeController handing a CoreData entity Detail Node.
Both of them are trees.
Project Node entity has a Relationship to Detail Node, allowing the Project tree show the detail tree depending on the selection.
The Problem I have is when I bind the contentObject in Detail NSTreeController to Master NSTreeController selection:
Detail NSTreeController contentObject binds to Master NSTreeController selection.detailNode
Every time I change the selection in Master tree outlineView, the detail NSTreeController creates a NSTreeControllerTreeNodes that never gets deallocated.
Basically with every Master controller selection change, the detail NSTreeContrller creates a new set of new NSTreeControllerTreeNode objects, that never gets deallocated.
Have a look at Instruments Allocation tool, every time you change selection the new nodes are created. Even after deleting all Master Nodes, the nodes are still allocated.
I have tried to prepare a NSViewController making to reload a new nib file with Master controller selection change, but this seems to me like a big overhead.
Anybody knows how to dispose the created NSTreeControllerTreeNodes when the contentObject bind changes to another value?
Thanks.

Core Data Multiple FetchedResultsController/Views: How do you update all manually?

I have two instances of the same ViewController class accessed in different tab items. Both use the same entity, but with a different predicate. One displays all the items, while the other displays a subset based on its predicate.
The problem occurs when I delete an object from the "All" list. It updates immediately, but when I switch over to the other tab, the object is still there, even after going back and forth in the views. Only after a period of time, around 5 to 10 seconds, does the deletion get reflected in the other view.
The ViewController class use a FetchedResultsController.
Any ideas what the cause is and how to get the results to immediate appear?
Just put a reloadData into viewWillAppear. You can also catch this when the tab bar's selected index changes.
Apparently, there is no solution. There is no way to update UIManagedDocument manually.
This guy came to the same conclusion:
Core Data managed object does not see related objects until restart Simulator
So the solution is to use the default master-detail template and to stop using UIManagedDocument. Wish there was some documentation on this, would have saved me a day of my life.

Reverting CoreData data

I have an NSTableView which is populated via a CoreData-backed NSArrayController. Users are able to edit any field they choose within the NSTableView. When they select the rows that they have modified and press a button, the data is sent to a third-party webservice. Provided the webservice accepts the updated values, I want to commit those values to my persistent store. If, however, the webservice returns an error (or simply fails to return), I want the edited fields to revert to their original values.
To complicate matters, I have a number of other editable controls, backed by CoreData, which do not need to resort to this behaviour.
I believe the solution to this problem revolves around the creation of a secondary Managed Object context, which I would use only for values edited within that particular NSTableView. But I'm confused as to how the two MOC would interact with each other.
What's the best solution to this problem?
The easiest solution would be to implement Core Data's undo functionality. That way you make the changes to Core Data but if the server returns the error, you just rollback the changes. See the Core Data docs for details.

How to handle entity creation/editing in a master-detail

I'm wondering what strategies people are using to handle the creation and editing of an entity in a master-detail setup. (Our app is an internet-enabled desktop app.)
Here's how we currently handle this: a form is created in a popup for the entity that needs to be edited, which we give a copy of the object. When the user clicks the "Cancel" button, we close the window and ignore the object completely. When the user clicks the "OK" button, the master view is notified and receives the edited entity. It then copies the properties of the modified entity into the original entity using originalEntity.copyFrom(modifiedEntity). In case we want to create a new entity, we pass an empty entity to the popup which the user can then edit as if it was an existing entity. The master view needs to decide whether to "insert" or "update" the entities it receives into the collection it manages.
I have some questions and observations on the above workflow:
who should handle the creation of the copy of the entity? (master or detail)
we use copyFrom() to prevent having to replace entities in a collection which could cause references to break. Is there a better way to do this? (implementing copyFrom() can be tricky)
new entities receive an id of -1 (which the server tier/hibernate uses to differentiate between an insert or an update). This could potentially cause problems when looking up (cached) entities by id before they are saved. Should we use a temporary unique id for each new entity instead?
Can anyone share tips & tricks or experiences? Thanks!
Edit: I know there is no absolute wrong or right answer to this question, so I'm just looking for people to share thoughts and pros/cons on the way they handle master/details situations.
There are a number of ways you could alter this approach. Keep in mind that no solution can really be "wrong" per se. It all depends on the details of your situation. Here's one way to skin the cat.
who should handle the creation of the copy of the entity? (master or detail)
I see the master as an in-memory list representation of a subset of persisted entities. I would allow the master to handle any changes to its list. The list itself could be a custom collection. Use an ItemChanged event to fire a notification to the master that an item has been updated and needs to be persisted. Fire a NewItem event to notify the master of an insert.
we use copyFrom() to prevent having to replace entities in a collection which could cause references to break. Is there a better way to do this? (implementing copyFrom() can be tricky)
Instead of using copyFrom(), I would pass the existing reference to the details popup. If you're using an enumerable collection to store the master list, you can pass the object returned from list[index] to the details window. The reference itself will be altered so there's no need to use any kind of Replace method on the list. When OK is pressed, fire that ItemChanged event. You can even pass the index so it knows which object to update.
new entities receive an id of -1 (which the server tier/hibernate uses to differentiate between an insert or an update). This could potentially cause problems when looking up (cached) entities by id before they are saved. Should we use a temporary unique id for each new entity instead?
Are changes not immediately persisted? Use a Hibernate Session with the Unit of Work pattern to determine what's being inserted and what's being updated. There are more examples of Unit of Work out there. You might have to check out some blog posts by the .NET community if there's not much on the Java end. The concept is the same animal either way.
Hope this helps!
The CSLA library can help with this situation a lot.
However, if you want to self implement :
You have a master object, the master object contains a list of child objects.
The detail form can edit a child object directly. Since everything is reference types, the master object is automatically updated.
The issue is knowing that the master object is dirty, and therefore should be persisted to your database or whatnot.
CSLA handles this with an IsDirty() property. In the master object you would query each child object to see if it is dirty, and if so persist everything (as well as tracking if the master object itself is dirty)
You can also handle this is the INotifyPropertyChanged interface.
As for some of your other questions :
You want to separate your logic. The entity can handle storage of its own properties, and integrity rules for itself, but logic for how different object interact with each other should be separate. Look into patterns such as MVC or MVP.
In this case, creation of a new child object should either be in the master object, or should be in a separate business logic object that creates the child and then adds it to the parent.
For IDs, using GUIDs as the ID can save you quite a bit of problems, because then you don't have to talk to the database to determine a correct ID. You can keep a flag on the object for if it is new or not (and therefore should be inserted or updated).
Again, CSLA handles all of this for you, but does have quite a bit of overhead.
regarding undo on cancel : CSLA has n-level undo implemented, but if you are trying to do it by hand, I would either use your CopyFrom function, or refresh the object's data from the persistance layer on cancel (re-fetch).
i just implemented such a model.but not using NH, i am using my own code to persist objects in Oracle Db.
i have used the master detail concept in the same web form.
like i have master entity grid and on detail action command i open a penal just below the clicked master record row.
On Detail Add mode, i just populate an empty entity whose id were generated in negative numbers by a static field.and on Save Detail button i saved that entity in the details list of the Master Record in Asp.NET Session.
On Detail Edit,View i populated the Detail Panel with selected Detail through ajax calls using Jquery and appended that penal just below the clicked row.
On Save Button i persisted the Master Session (containing list of Details) in database.
and i worked good for me as if multiple details a master need to fill.
also if you like you can use Jquery Modal to Popup that Panel instead of appending below the row.
Hope it helps :)
Thanks,

Resources