I have a Core Data entity, which contains a relationship to another entity. Under certain circumstances, I need to delete the managed objects in the relationship, and at other times no action needs to be taken.
I have the Delete Rule on the entity is No Action because of this manual management.
The problem I have is, where is the best place to enforce these rules? I cannot see any suitable messages to override on NSManagedObject (something that might notify the object it has been deleted and should clear up its relationships).
I would rather not do it higher up in the application logic, because the entity objects can get deleted from array controllers and at different points in the applications, making it necessary to stuff relationship update code at all those levels.
In your NSManagedObject subclass, override the -prepareForDeletion method and handle the logic there.
UPDATE
You did not specify that you need a solution for retired versions. In that case you can handle it in the -save: call. Just before the save, grab the array of objects to be deleted, iterate over them and then call -prepareForDeletionon each object if it responds to it (using-respondsToSelector:`) and that gives you a future proof way to handle the deletions. You will of course need to check to see if you are running 10.6 or an earlier OS before running this code but that is fairly trivial to write up.
Related
I'm trying to figure out what is the best way to handle a quite commons situation in medium complex apps using Flux architecture, how to retrieve data from the server when the models that compose the data have dependencies between them. For example:
An shop web app, has the following models:
Carts (the user can have multiple carts)
Vendors
Products
For each of the models there is an Store associated (CartsStore, VendorsStore, ProductsStore).
Assuming there are too many products and vendors to keep them always loaded, my problem comes when I want to show the list of carts.
I have a hierarchy of React.js components:
CartList.jsx
Cart.jsx
CartItem.jsx
The CartList component is the one who retrieves all the data from the Stores and creates the list of Cart components passing the specific dependencies for each of them. (Carts, Vendors, Products)
Now, if I knew beforehand which products and vendors I needed I would just launch all three requests to the server and use waitFor in the Stores to synch the data if needed. The problem is that until I get the carts and I don't know which vendors or products I need to request to the server.
My current solution is to handle this in the CartList component, in getState I get the Carts, Vendors and Products from each of the Stores, and on _onChange I do the whole flow:
This works for now, but there a few things I don't like:
1) The flow seems a bit brittle to me, specially because the component is listening to 3 stores but there is only entry point to trigger "something has changed in the data event", so I'm not able to distinguish what exactly has changed and react properly.
2) When the component is triggering some of the nested dependencies, it cannot create any action, because is in the _onChange method, which is considering as still handling the previous action. Flux doesn't like that and triggers an "Cannot dispatch in the middle of a dispatch.", which means that I cannot trigger any action until the whole process is finished.
3) Because of the only entry point is quite tricky to react to errors.
So, an alternative solution I'm thinking about is to have the "model composition" logic in the call to the API, having a wrapper model (CartList) that contains all 3 models needed, and storing that on a Store, which would only be notified when the whole object is assembled. The problem with that is to react to changes in one of the sub models coming from outside.
Has anyone figured out a nice way to handle data composition situations?
Not sure if it's possible in your application, or the right way, but I had a similar scenario and we ended up doing a pseudo implementation of Relay/GraphQL that basically gives you the whole tree on each request. If there's lots of data, it can be hard, but we just figured out the dependencies etc on the server side, and then returned it in a nice hierarchical format so the React components had everything they needed up to the level where the call came from.
Like I said, depending on details this might not be feasible, but we found it a lot easier to sort out these dependencies server-side with stuff like SQL/Java available rather than, like you mentioned, making lots of async calls and messing with the stores.
What are the major disadvantages in using a form bean with session scope in struts 1.x?
You need to implement reset() if your form contains attributes populated from checkboxes. You don't need that to request-scoped form beans.
You need to reset the form to its default values if you show a creation form for the second time, else the creation form will redisplay the data coming from the last created/updated object.
You can't have two browser tabs or frames using the same form, because they will walk on each other's toes.
Form beans should be in the request scope by default.
Just try to work with both scopes and choose one preferred for yourself. But I should say there is small difference when you are working with persistent objects (and ORM tools like Hibernate), just because properties are persisted in database between requests.
Infamous checkboxes (and corresponding boolean properties). If you are working with persistent objects (editing boolean properties of some entity), you'll need extra code to reset checkboxes anyways. Scope doesn't matter because boolean property is persistent (isn't cleared automatically between requests).
When you are working with complex persistent objects (hierarchies of objects, mapped by Hibernate onto set of related database tables), often you'll just nest persistent object into form-bean and use nested properties, e.g. <html:text property="purchase.client.name" /> (of course, you can create getters/setters in form-bean for each property of the entire hierarchy, but this is tedious and will complicate further development). For creation you'll just create new empty purchase object in form-bean, for edition you'll load existing purchase from database (request for edit will contain some identifier of object you want to change). Scope doesn't matter again.
About two browser tabs. More important and underestimated problem arises with usage of AJAX requests, especially when they are not idempotent and are overlapped in time (browser issues request for update 1, then request for update 2, while update 1 is still processed on server) - although it is very strange design (I mean overlapping update requests simultaneously in one session from one user). Yes, in that case you'll need to separate data in different requests. But moreover, your action (if we are talking about Struts 1) should be thread-safe, and your business logic should be ready to concurrent/conflicting updates (solve synchronization problems, lock objects, merge/override/reject updates etc.). If you are developing multi-user application, this may happen also when two different users want to change the same object simultaneously. Again, bean scope has little importance comparing to the whole problem.
As you can see, there is only one disadvantage with session-scoped form bean, and it arises only in relation to serious design flaw (overlapping update requests from one user).
Is it possible to have one model that you break up into several views so that the user is not overwhelmed by the amount of data they will need to input? I'm trying to build a turbo tax like interface where a question or two are asked, then the user clicks next to answer the next set of questions and so on.
The Model doesn't seem make sense to break up into more models. Since it is a single distinct entity, like a questionnare.
See similar question for a nice example:
multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)
It is possible to use the same model for multiple views, but you should decide how you want to preserve the state as you go though this "wizard". One approach can be to cross-post between the views and keep the state in post data, but in that case you have to add a lot of hidden fields for all model properties that are otherwise not displayed in an input on the current view. Another approach can be to persist the partially filled model, with the additional benefit, that the user might be able to continue after a session timeout or another problem, but then you might need to clean up stale data and be flexible in the validation on the database level. You can also preserve the state in the session if you want. Finally, you can also keep the state in the browser independent from the post data and do only AJAX calls with the server until you reach the point when you want to save everything.
So I've got an .xcdatamodel with about a dozen Entities defined and related to each other, with attributes and so on. So far I've been trying this in to a GUI using NSTableViews to display/enter data, and NSArrayControllers that I instantiate for each entity. This is all working great. They all tie in to the App Delegate's Managed Object Context (MOC)
But now I'm trying to programmatically access the data in these arrays, and I'm finding it obtuse to do so. After a lot of reading it looks like what I should REALLY do is go to the MOC to fetch data for a given Entity. I haven't worked through this yet, but ok.
What I don't understand though, is how to use Core Data when I'm NOT entering via NSTableView etc, and NOT using NSArrayControllers. Like if I wanted to totally handle some of my .xcdatamodel Entities in my project's Model packages (that don't touch a GUI). Do I need to still instantiate an NSArrayController so that I can "prepare content" of an Entity and have it be managed and initialized and all that? Or is there another way I can tie in with the MOC directly and add/remove/get the data for a given Entity?
What I'm saying is that I'm really unclear as to how to work with things unless I'm doing simple case View <-> NSArrayController and then Model <-> MOC
You should take a look at NSFetchRequest and the executeFetchRequest:error: method on NSManagedObjectContext.
Accessing the data via the array controller can be tricky. I've found that array controllers are generally designed to be used with UI elements. There are some tricks that the array controller will use to keep the UI snappy. It will fetch items on a background thread, for instance. Much of this can be configured, but you'll be better off accessing the info doing your own fetch.
The NSArrayController and related classes are intended to serve as off the shelf MVC design controllers. As such their only real function is to link the UI to the data model. If you need to deal with the model otherwise, you usually do so programmatically.
To access the model programmatically, you usually start with a fetch request (NSFetchRequest) to find the appropriate instances of certain entities. Then you would walk the entity relationships to find all other instances of the entities related to the fetched entities.
For example: Suppose you had a schedule type app. You entities are days and events. Each day has several events but each event has only one day.
If you want to check the events for a week, you would fetch the day objects whose date attribute feel in the 7 day range. Then you would ask each day object in turn for its related events.
The iOS does not yet support binding so check out the resources for using Core Data there to see how to manage all this manually.
Let's say I have a GUI with multiple types of viewers of user objects. For example, a tree view, a list view and a diagram view. The three views show the same objects. If a user deletes an object from one view, I would like to fire off an event to notify the other two views. I currently do this by exposing an event on the object itself. So if the object is deleted from View 1, View 1 will call delete on the object, which will then fire an event to the subscribers (all 3 views). Each subscriber has the chance to cancel the deletion.
There are a few problems as I see it. If a subscriber cancels a deletion after another subscriber has already approved of the deletion, then I have to instruct those subscribers to undo the deletion.
Are there any good patterns to implement this kind of common scenario?
If an object is to be deleted from all views, or no view at all
Ask every subscriber if it's ok to delete the item; if yes:
Issue a "delete item" call to remove the object from the source, perform a soft delete or whatever you'd like
Update each view. This would be the observer part, listen for a "object deleted" call and take appropriate actions, for example manually remove the now deleted object from each view
If you always want the user to be able to delete the object from its own view:
Step 2. from above, with the addition that it's only been deleted either for 1) the user; or 2) that user in that view
Step 1. from above, and continue.. (might be skipped, depending on how much you'd like the views to be coherent)
The twist here is that each subscriber has the chance to cancel the deletion. Normally, when you use the words "view" and "subscribe", it means that you are being passive and just reacting to what you see.
That doesn't mean that what you're trying to do is impossible, but it's definitely tricky. For example, you could try to do a sort of two-phase commit, where you mark the object is deleted and then wait for all of the viewers to acknowledge the deletion before really removing the object. (This is basically the "ask every subscriber if it's OK to delete the item" approach that chelmertz suggests.) However, this means you need to know exactly how many viewers there are, and all viewers will need to respond before you can complete the deletion. Do you always have three viewers? Are there ever only two? What if there is an error in one of the viewers - Should the delete fail, or do you want to go ahead and delete the object anyway?
The nice thing about an event-driven system is that you don't normally have to worry about these sorts of questions: You just make your change to the model (in this case, delete the object) and fire a change event. You don't need to know anything about your viewers.
So, if this were my system, I would try to figure out a way to make model changes cancelable only before they are applied to the model, rather than trying to apply changes to other views through the model and then trying to roll back those changes later.