I have a navigation property, which I added a custom validator to.
The validator triggers fine when saving the entity. However it does not trigger when adding/removing entities from the navigation property.
Should I subscribe to propertyChanged event, or is there another way to handle this ?
Also, why is there not a propertyChanged event per property instead of having to subscribe to any properties change ?
There are two kinds of navigation properties, scalar and nonscalar. A scalar property is something like 'Order.Customer' where an order has a single customer associated with it. Setting or changing the customer in this case will fire the entityAspect.propertyChanged event.
For a nonscalar property like say 'Customer.Orders', accessing the property returns an array of orders associated with the customer.
This is always the same array. Orders can be added or removed from it, but the returned array itself is always the same. Because the array itself is never changed a property change is NOT fired for these operations.
However you CAN watch the array itself for changes, see the arrayChanged event
in the breeze Api docs.
As for why there is no separate event that you can register to fire only when a specific property is changed, the reason is that the current mechanism supports your ability to do this while at the same time allowing for those use cases where you want to see 'all' of the changes to an entity without having to register what could potentially be tens of thousand of events.
Remember entity property level events, if they existed, would have to be registered on as many entities as are in your cache (100's or 1000's) times the number of properties on your entities (5-50).
Most of what is described here is fairly standard for entity change tracking in a number of environments across a variety of programming languages. We didn't try to reinvent the idea, but simply reimplemented a pretty common standard.
Related
Working on a project that will display hierarchies of "tasks". I'm running into a problem where it will not allow for multiple entries of the same object. From what I can tell, the "duplicate" item is under a different parent.
The domain data allows for this - a given task may appear in lots of places.
It would seem that this is intentional (maybe), but is there a way around this?
It's intentional to a degree; each Grid and TreeGrid data item is expected to be unique. You could work around this by creating your own implementation of the hierarchical DataProvider class (for example extend AbstractHierarchicalDataProvider) which overrides the getId method along with the other required methods. The return value of this method needs to be unique per item, as it's used as a hash key.
Well, this is probably not the best solution, but it works.
I added a field to the abstract super class that is initialized with the current time (long ms). When I am adding items to the tree grid, I check to see if the tree contains the item and if so, I randomize the field and then add it. The new field is marked #Transient so it's not persisted.
I am using coreData in a chat app. I want to set each messages messageViewed bool attribute to true anytime I fetch all messages in a chat room.
Of course I could do this by first fetching all the messages in a room and then iterating through each message and setting the messageViewed attribute to true, however I am looking for a more efficient way of achieving this.
I remember reading somewhere that it may be possible during the fetch to define or change the value of an entity's attribute for all items fetched directly in the fetch request but I can't remember where I read that or how to implement it.
awakeFromFetch is method you're talking about.
But be careful about it's behaviour:
The managed object context’s change processing is explicitly disabled around this method so that you can use public setters to establish transient values and other caches without dirtying the object or its context. Because of this, however, you should not modify relationships in this method as the inverse will not be set.
I am using Core Data to model an entity which has both attributes and relationships. I would like to make one of the attributes dependent on two other relationships.
The Core Data FAQ and several other examples use +(NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key for this purpose. However, this only seems to be called for all of my relationship properties, but not for any of the attributes. In addition keyPathsForValuesAffecting<key> never gets called for any of my attributes.
Is this the normal behaviour or am I missing something? How can I calculate one attribute based on other attributes or properties, eg. a distance, by setting a startLocation and a stopLocation?
It looks like a found the solution to my own problem after a couple of days and it turns out I was missing something.
After rereading the discussion of the method keysPathsForValuesAffectingValueForKey: in the NSKeyValueObserving Protocol Reference, I realized the meaning of the following sentence:
When an observer for the key is registered with an instance of the receiving class, key-value observing itself automatically observes all of the key paths for the same instance, and sends change notifications for the key to the observer when the value for any of those key paths changes.
In short, your instance should have an observer observing changes to your attribute <key>:
[myInstance addObserver:myObserver forKeyPath:attributeKey options:nil context:nil];
As soon as you have an observer registered, the protocol will call keysPathsForValuesAffectingValueForKey for your specific attribute key. If this method returns a non-empty set of key paths, KVO will emit a change notification for your attribute, if a change is made to any of these key paths, in addition to notifying you of any direct change to your attribute.
Relationship keys do get called automatically, because Core Data already uses observers to keep inverse relationships up to date.
In the particular case where you want to have an attribute depend on another attribute or relationship within the same entity, you will have to:
Add an observer in the awakeFromInsert: method using addObserver:forKeyPath:options:context:
Implement keyPathsForValuesAffectingValueForKey: or keyPathsForValuesAffecting<key>
Implement observeValueForKeyPath:ofObject:change:context for your attribute key path to act on the relevant change notifications, i.e. updating your attribute value.
I often have a UITableViewController with an edit button, which I like to disable when there are no rows in the table. To keep this in sync, I enable/disable the button every time something happens that might update its dataSource - adding the first row, deleting the last row, in viewDidLoad, etc. Whenever I add some new functionality that can affect the contents of the table, I have to remember to incorporate this logic.
Is there some delegate of the UITableView that I can use to simplify this? A way to know whenever the table (or it's dataSource) is modified, where I can check the number of items in the dataSource and enable/disable accordingly.
Alternatively, any other approaches would be welcomed.
You are the data source. So you do know whenever the data source changes, if you care to know. In other words, the reason you're having this problem is that you're treating the model (in the model-view-controller architecture) as an alien being. Instead, treat the model as something of your own. Take charge of your model. For example, is the model an array? Then wrap it in a class of your own, to which all commands to change the array must be given. That way, it can emit a notification whenever it is told to change the array.
It is also possible under certain circumstances to use Key-Value Observing to get notified when something changes, and you could look into it, but with primitives like arrays and dictionaries it is possible that this will be more trouble than it's worth. Again, you're likely to be happier wrapping your model storage in your own class, whose observability via KVO you can manage yourself.
I am working on a shopping list app, and I have a couple of cases where I need to watch for changes to an entity, and respond by making changes to other entities. For example:
When a new store entity is added, I need to create related aisle entities.
When the quantity is changed on a food item to 0 or >0, I need to set a related state flag on the item (ftr, the flag has more than two states, I can't just drop the flag and test for 0).
Based on what I've read so far, the choices seem to be between using key-value observing & registering for a NSManagedObjectContextObjectsDidChangeNotification. What I'm not sure of is which is more suited to my scenarios (or if I should just override the appropriate methods in the related entity classes). Any pointers and/or documentation on when to use these would be much appreciated.
If the flag is a sort of derived property from the quantity information, then your best approach might be to override the setter for the quantity in your managed object subclass and update the flag there. Since the flag is a model property, it makes sense to keep responsibility for its value in the model, rather than in a view controller or other non-model object that's using KVO or responding to notifications.
You can to use NSFetchedResultsController instead of notifications. Also, you can modify your entity to have class methods to add these new records, and manage whatever other modification you need to do.