Reverting CoreData data - object

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.

Related

Catel using IEditableObject

I am testing Catel MVVM and I would like to use the implemented IEditableObject. I have got some questions, but the documentation I've found, isn't very detailed in this point.
Did someone have a helpful link, how I have to set this up or how it works, or something like this? Or should I really have a look to the source code, to get these points and get a feeling, how catel do the work.
The questions, that I have got, are these:
What exactly does the method SaveViewModelAsync()?
Where does it save the data, or where can I configurate it?
How can I use it with Orc.EntityFramework6, or do I have this manually?
What's the different between SaveViewModelAsync() and SaveAsync()?
What's the different between CancelViewModelAsync() and CancelAsync()?
I can only cancel the editing one time. If I edit the same ViewModel again, the cancel has no effect anymore.
I think there is only an BeginEdit() missing after the first cancel, like this documentation suggests. Here some informations to this point:
I edit the ViewModel and the Model set the new value
I execute CancelViewModelAsync(), the setter in the Model is not touched
I edit the ViewModel and the Model set the new value. The current value is the original value
I execute CancelViewModelAsync(), nothing happened
I edit the ViewModel and the Model set the new value. The current value is the edited value from step 3, like the View shows
Thanks for help
Lots of questions in a single question, but will try to answer them:
Q1) What exactly does the method SaveViewModelAsync()
It calls IEditableObject.EndEdit on all models that support it (and are decorated with the ModelAttribute
Q2) Where does it save the data, or where can I configurate it?
It just approves the changes to the model, it doesn't "save" anything. So for example, if you are using Catel models, it will commit the changes made by the VM. If you would cancel, it would revert the model back to the state it was when you initialized the VM.
Q3) How can I use it with Orc.EntityFramework6, or do I have this manually?
You have to do this manually. The VM's in Catel work with models, it's up to you when / where you persist them to (e.g. a database, disk, web service, etc)
Q4) What's the different between SaveViewModelAsync() and SaveAsync()?
SaveViewModelAsync is the public method being called and takes care of the plumbing for you. SaveAsync is a method you can override to add additional save logic (e.g. storing in database, update services, etc).
Q5) What's the different between CancelViewModelAsync() and CancelAsync()?
See Q4

Update Kentico document field regardless of versioning

I have a field on one of my base page types which I need to update programmatically from an external data feed, so that it can be included in my Smart Search index.
The documents are versioned, but I want to update the published value of this field regardless of checkout state, and obviously avoid any sort of overwrite when documents are checked in.
The field will not appear on the editor form -- or ideally, would conditionally display for Global Admins.
It appears that using the API to update the document without doing a CheckOut fails silently. However if I do a Checkout/Update/CheckIn on a checkout-out page, the author will lose their work I assume?
Any way to handle this "versionless" field via the Kentico data model and API?
I don't think there is a way around updating checked out pages. You can update the page type table directly, but as you mentioned, it will be overwritten when they check in. You could update the version history I believe to make changes to the current data that is checked out, but again, I think that will be lost if the user cancels.
The only way I can think of to solve your issue is to create another table that maps the values you want to the page. Then you don't have to worry about the pages being checked out, you just need to grab the documentID or something. Since the value isn't displayed to the editor, you just have a field that does a lookup on this table.
The preferred and right way is using the API but as you stated, it causes problems if a user has something already checked out and working on it or it's in workflow and not published yet.
If the field you're updating is page type specific, there is one thing specifically I can think of and that's going directly to the database to the page type's database field and perform an update to that field.
Note: this is not recommended unless you know specifically what you're doing and have done full testing on it
The down side of going direct to the database is this will not update the current version since you're using check in/out and workflow. You will also need to update the checked out and current version which means you need to:
Go to the Document itself in the cms_documents table and get the document you are working with.
Then using the fields DocumentCheckedOutVersionHistoryID and DocumentPublishedVersionHistoryID' you can get the version history IDs of the document from theCMS_VersionHistory` table.
Then you can perform an update to the CMS_VersionHistory and your custom page type fields.
You will then need to look in the CMS_WorkflowHistory table and find out if that document is in workflow and in what step.
After you have that workflow history step, use the VersionHistoryID field to go back to the CMS_VersionHistory table and update that record with your data.
Again, not an elegant solution since you are using check in/out and workflow but after some trial and error and testing you should be able to figure it out.
UPDATE
You may also be able to add a custom table or some other linked database table which will allow you to create a global handler. The linked table would be where you perform your updates via API and other calls without versioning or workflow. Then when a user updates a specific page type you could do a check to see when the last time that linked table was updated and update the field(s) you need on update of that particular page (of course by node and document IDs).
Unfortunately you'll have to check it in and out with API. See examples here.
Also you might need to publish it in order to reflect changes on the live site.

MVC 5 Save Drafts While Ignoring Missing Required Fields

I have searched for current solutions, but can't find a set of guidelines or examples as to how to achieve the following:
The original requirements involved models with required fields, so we included annotations to those fields. As usual, there is a last-minute change and we are being asked to allow the users to save drafts. These drafts must allow the user to save the forms without any of the required fields.
I would like to know what the best practices for this problem are.
Solutions I am considering, but I accept they might be a hack (and that's why I am asking the experts)
If the user clicks "Save as Draft" I can capture the fields that have information in another ActionResult and run basic validation on those fields. Since there is a chance that required fields are missing, I am thinking in storing the captured info in a temporal model (without any required annotations). If the user decides to edit such form, I can populate fields in the view with the temp. model until the user clicks on "Submit"
Another option is to remove all required annotations and run client-side validations... but am wondering on the amount of work required to do so.
Any thoughts are very much appreciated.
Just have 2 save methods. 1 which is called from the autosave and 1 that is used to submit the process. In the autosave method do not check if(ModelState.IsValid).
Whether you choose to save the incomplete objects to the same table or a different table is your choice. In a relational world I would likely use a separate table, in a non-relational world I would use a singular object collection.
This will allow you to keep the same set of original models. There is a very high cost to duplicating your models, there are certainly times that warrants pass by value/copy but make sure the cost of mapping is there. In this situtation I do not believe there is value in mapping, except perhaps at the persistence level if you need to map to a different object because of an ORM's constraints.
There is deep value in these partial forms. Recording this on the server will allow you to apply analytics to learn why your users abandon your processes. It also gives you the ability to follow up on users who leave incomplete forms such as sending a reminder (nag) email.
You don't want to save anything to your database until it is complete. Having a duplicate table where everything is nullable is cludgy as hell. Before HTML5, the typical path was to save the information to the session, which you could then pull from to refill the fields, but that's requires having a session with a relatively high expiry to be useful.
Thankfully, HTML5 has local storage, which is really the best way to handle this now. You just watch for onchange events on your fields and then insert that value into local storage. If the user submits the form successfully, you destroy the local storage values. Otherwise, you attempt to read those values from local storage when the page loads and refill the fields.
See: http://diveintohtml5.info/storage.html
There's pretty broad support, so unless you need to worry about IE6 or IE7, you won't have any issues.
Another option (depending on your data obviously) would be to comply with the database but not the model. By this I mean ignore Model.isValid and disable Javascript validation on the front end but then satisfy the database table. In a form, you mostly have:
textboxes - default to "" or " "
checkboxes - easy true/false default
radio buttons - one is probably already selected
dates - default to DateTime.MinValue (or DateTimeUTC)
enums - default to 0 (usually for 'unspecified')
Hopefully you are also saving a flag designating that it is in Draft state so that you know you need to interpret the 'null codes' you have set when it comes to displaying the semi-populated form again.

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.

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