What method will be called by Core Data on NSManagedObject when setting a value for to-one relationship? What method will be called when adding a value to to-many relationship? Thanks.
/Mikael
Maybe you are looking for something like:
Managed Object Accessor Methods - Core Data Programming Guide
Its like this
managedObjectInstance.property = value;
[self.managedObjectContext save:&error];
Ex: if you want to save username in user entity it will be
_userEntity.username = #"Mikeal Hakman";
[self.managedObjectContext save:&error];
One to Many or Many to May always carries NSSet example
_residenceEntity.Seller = [NSSet setWithObjects:seller, nil];
[self.managedObjectContext save:&error];
Obviously I didn't manage to formulate my question clearly enough. I'll try again.
In a subclass of NSManagedObject I need to know when to-many and to-one relationships are being changed. That includes the very first change when the object is being fetched or inserted. I try all the accessors described in https://developer.apple.com/library/mac/documentation/cocoa/conceptual/coredata/articles/cdAccessorMethods.html to no avail. I can see in my UI that the relationship is there but no accessor methods has been called on my object. Also when I remove the relationship, it goes away in UI but no methods on my object are called. Thanks.
/Mikael
Related
Quirk I just discovered, and wanted to confirm with anyone here whether or not this is avoidable. Basically, if I have a very simple two entity model:
With a to-many relationship between Entity1 and Entity2. The relationship is optional, with nullify as the delete rule on both sides. However, if I insert a new Entity1 the value of the children relationship will be an empty set, not nil:
NSManagedObject *object = [NSEntityDescription
insertNewObjectForEntityForName:#"Entity1"
inManagedObjectContext:[self managedObjectContext]];
assert([object valueForKey:#"children"] != nil);
Furthermore, I can't explicitly set the relationship to nil:
[object setValue:nil forKey:#"children"];
assert([object valueForKey:#"children"] != nil);
I have verified this in a new, minimal project and this appears to be a true implementation detail. The problem is, I would like to be able to differentiate between a nil value (representing currently unknown) and an empty set (truly a to-zero relationship). Does CoreData actually support this at all in a reasonably direct manner? Currently it seems not, which means I will have to find another (less direct) way to represent my model.
Thanks,
J
Short answer is no. You will always get an empty set back. If you need to know if an object structure is fully realized (my guess at what your goal is) then you would want to set an attribute on the object to say if it is fully realized or not.
My NSFetchedResultsController work great, as long as only "basic" attributes get changed. However if I have a label which is calculated and I'm changing some attributes influencing this label in another view controller on the navigation controller stack, this label doesn't get updated.
For example my label should show the amount of a budget position left saved in the entity SpendingCategory.
self.budgetLeftLabel.text = [NSString stringWithFormat:#"%# %#", [[self.spendingCategory getExpendituresAmount] getLocalizedCurrencyStringWithDigits:0], NSLocalizedString(#"left", nil)];
I derive this value from the category on SpendingCategory with this method:
- (NSNumber *)getExpendituresAmount
{
return [self.hasExpenditures valueForKeyPath:#"#sum.amount"];
}
However this label doesn't get any updates by the NSFetchedResultsController. And I have several locations in my app where this doesn't happen because a value is calculated. What do I need to change that these updates happen?
EDIT with datastructure:
Ok my Spending Category datastructure is roughly (for budget):
name (string)
cost (double)
position (integer 16)
Relationsships: hasExpenditures
My Expenditures structure (for tracking):
amount (double)
date (Date)
description (string)
Relationsships: forSpendingCategory
I hope it's clearer now. So why do these values not get updated?
The NSFetchedResultsController gets tickled when attributes in the relevant NSManagedObject instances are updated. If you are changing something that is purely calculated then the update never fires. Why is this relevant?
If you are changing something in the Expenditures entity (btw, entities should be singular in name) and you are watching the Spending Category entity then the NSFetchedResultsController won't fire because you didn't change anything that is relevant.
How to fix this?
Depends. I normally keep that derived value in the entity and persist it. Further, whenever a child changes a relevant value, I have the parent recalculate. This will cause the NSFetchedResultsController to fire.
How do you watch the values?
Either you have the child call a method on the parent (icky) or you have the parent watch the values on its children via KVO (better). Your personal preference decides here.
Update 1
To keep the derived value in the entity you add a new attributed to the entity and store it. Nothing is special about the attribute. It helps to keep in mind that Core Data is not a database. Core Data is your data model that happens to persist to a database if you so choose. Therefore you want to denormalize the database in cases like this.
while I was searching SO to find a good link for watching children, I stumbled across this example.
KVO object properties within to-many relationship
While the accepted answer is not very good, the second answer, using a NSFetchedResultsController is quite interesting and is worth exploring. The basic idea is that your parent objects instantiate a NSFetchedResultsController on -awakeFromFetch or -awakeFromInsert and when it fires, they recalculate the derived value. Thus the value is always up to date and your view controller based NSFetchedResultController instances will fire because the parent object has changed.
I did something similiar time ago, basically you need to store your calculated value in a transient attribute in your CoreData model, rather than implement your own setter and getter. Then in the related NSManagedObject you need to implement two methods:
// this will populate the values when
// the entity is retrieved from the store
-(void)awakeFromFetch {
[self refreshCellInfo];
}
// this will refresh the values when
// the object goes to fault
// (for example when it is off screen)
-(void)willTurnIntoFault {
[self refreshCellInfo];
}
-(void)refreshCellInfo {
// update all your derived values...
}
I've the following problem:
I have two or more persistent stores. And I have created an entity in the xcdatamodel named "House". Now I have these two files for the NSManagedObject House.
Now I want to know how do I save an instance of the entity house in a specific persistent store?
So I tried to work with [NSEntityDescription insertNewObjectForName:#"House" inManagedObjectContext:context] and [context assignObject: toPersistentStore:]. But it didn't worked until now. Am I on the right way to do it?
Can somebody give me a hint?
Answering my own question:
The problem was that I allocated a completely new persistentStoreCoordinate who coordinates all the stores. So the coordinator wasn't linked to the managedObjectContext.
Could be solved with
__persistentStoreCoordinator = [__managedObjectContext persistentStoreCoordinator];
I've got a few questions I've been trying to answer for myself (by hunting through the documentation) but I have a feeling I'm missing something.
Any hints (and/or pointers to appropriate documentation) would be much appreciated.
I'm building a Core Data document-based application. There are essentially two entities:
There is a single "Comparison" record associated with each document.
There are potentially many "Node" records associated with each document.
My first question is whether I'm thinking about this correctly. Since there is only a single Comparison object for each document, the attributes of the Comparison are essentially attributes of the Document itself. What (if any) is the preferred way of modeling that?
If a Comparison entity is in fact the right way to go, my next question is how and when to actually instantiate the (single) Comparison object. The user should not have to explicitly "add" the Comparison since there's going to be only one of them associated with the Document. Instead, a single Comparison object should be instantiated and inserted into the managedObjectContext. I've got something like this working already, with code in MyDocument.m that looks like this:
(void)windowControllerDidLoadNib:(NSWindowController *)windowController {
[super windowControllerDidLoadNib:windowController];
[NSEntityDescription insertNewObjectForEntityForName:#"Comparison" inManagedObjectContext:managedObjectContext];
}
However -- if the user creates a new document but then never does any work with it -- for example if he immediately clicks the close button -- then he should not be asked to "Save" the document. He should be asked to save his work only if he's actually entered any information. Is there a preferred way to implement this behavior?
I found this thread while struggling with the exact same issue. I have a table of Entity_A working in my document based Core Data app, but I need to figure out how to handle a required single-instance per document of Entity_B.
I've found something that seems to work. There's probably a better way, but this is getting me past this hurdle for now.
When the document's xib is loaded I simply check to see if an Entity_B has been created. if not, I create one and initialize its attributes.
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
//has an Entity_B been created? if not, create one.
NSError *theError = nil;
NSUInteger count = [[self managedObjectContext] countForFetchRequest:[NSFetchRequest fetchRequestWithEntityName:#"Entity_B"] error:&theError];
if( count == 0 )
{
NSManagedObject *newEntity_B = [NSEntityDescription insertNewObjectForEntityForName:#"Entity_B" inManagedObjectContext:[self managedObjectContext]];
[newEntity_B setValue:[NSNumber numberWithBool:YES] forKey:#"boolAttribute"];
[newEntity_B setValue:[NSNumber numberWithInt:2] forKey:#"intAttribute"];
}
}
I didn't insert that code snippet into the original post correctly. Trying again:
-(void)windowControllerDidLoadNib:(NSWindowController *)windowController {
[super windowControllerDidLoadNib:windowController];
[NSEntityDescription insertNewObjectForEntityForName:#"Comparison" inManagedObjectContext:managedObjectContext];
}
Your question about modelling is not very clear, can you please elaborate on what your "Comparison" entity is supposed to do and what sort of attributes you are assigning to it? It would be handy to see your "Document" entity structure so we can provide some useful input.
With regards to your second question, you could check if your NSManagedObject has been updated before deciding on whether to prompt the user to save their document or not:
if ([documentObject isUpdated]) {
...
}
More details in the documentation here http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/Reference/NSManagedObject.html#//apple_ref/occ/cl/NSManagedObject
Cheers,
Rog
There isn't really a "Document" entity, I was simply using that term to refer to the overall document that is saved when the user invokes the Save menu item. Perhaps there is a better way to refer to this concept? NSPersistentDocument?
Backing up a bit... the central idea of the application is to compare two hierarchical directory structures (a visual recursive "diff").
For now the "Comparison" entity has two string attributes, pathA and pathB, which are the names of the two directories to be compared. Each "Node" entity represents the name of a file down in the directory trees that are being compared. The Node entity contains at least one attribute ("relativePath") which is the path relative to the starting point specified in the Comparison.
My first question was simply whether it makes sense for there to be a "Comparison" entity since there is going to be only one of them instantiated (at some point after the user invokes the "New" menu item).
The second question is really at what point should the single "Comparison" object be instantiated and inserted into the managedObjectContext, i.e. what method is most appropriate to make this happen?
Finally if a "Comparison" object is automatically instantiated (at awakeFromNib time, perhaps?) but the user decides not to proceed, and simply clicks the close button, he should not be prompted to save (right?) What would be the appropriate way to accomplish this? The documentObject will appear to have been updated, because an "empty" Comparison object has in fact already been inserted automatically at startup, but the user has not modified it.
Hope that's clear... thanks.
Dear all.
Currently i need to extract necessary objects from core data but i have just attribute name in entity. TO setup reverse relationship, i find just one way to loop around all objects in managed objects, compare strings for checking necessary attributes accordance and setup relationship. May someone have better way. relationship carrier is part of NamesTranslationRules Entity and connect to Carriers Entity
NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Carriers"
inManagedObjectContext:moc]];
NSArray *carriers = [moc executeFetchRequest:request
error:&error] ;
for (NSManagedObject *carrier in carriers)
{
if ([[carrier valueForKey:#"name"] isEqualToString:[tempRules valueForKey:#"carrier"]]) [namesTranslationRules setValue:carrier forKey:#"carrier"];
}
A parent object's is create at application startup as carrier's name with some attributes. Later user have to choice a name from another source and based on user's choice we have to add appropriate entity, which have already present parent entity carrier.
What do you mean by a reverse relationship? If the relationship is already bi-directional then the reverse will be set up for you automatically by Core Data.
If you mean something else, you can look at using a predicate on your NSFetchRequest to pre-filter the objects and skip the string comparison.
Update 1
You should know the parent object at the time of the creation and should be connecting them at that time.
Where is the data coming from?