I have 2 autogenerated entities :
#interface ContactEntity : Entity
#property (nonatomic, retain) NSString *caption;
#property (nonatomic, retain) NSString *image;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *text;
#property (nonatomic, retain) NSSet *pointLink;
#end
#interface PointEntity : Entity
#property (nonatomic, retain) NSNumber *latitude;
#property (nonatomic, retain) NSNumber *longitude;
#property (nonatomic, retain) NSSet *entityLink;
#property (nonatomic, retain) EntityEntity *entityTypeLink;
#end
They are linked between each other as ManyToMany, i.e. one contact has many points, one point has many contacts inside.
Then a i get first entity :
ContactModel *contact = [[[ContactModel alloc] init] autorelease];
// this is FetchRequest, returns array of all entities
self.items = [contact list:contact];
// i get only one, all is OK here, this entity has related PointEntity in DB
ContactEntity *contactEntity = [self.items objectAtIndex:self.selection];
And when i try to get related PointEntity using NSSet in selected ContactEntity i always get NULL or empty array. Neither of this works :
NSArray *points = [contactEntity.pointLink allObjects];
PointEntity *pointEntity = [contactEntity.pointLink anyObject];
NSInteger x1 = [points count]; // always 0
id x2 = pointEntity.latitude; // always 0
for (PointEntity *x in contactEntity.pointLink) // isn't enumerated because count = 0
{
id x3 = x.latitude;
}
Any thoughts are appreciated. Did i miss something, maybe i need to use NSPredicate to select entities from PointEntity that are related to ContactEntity?
Thanks.
P.S. My question is similar to this but that suggestion does not work for me, i cannot get loaded associated entities using NSSet of main entity :(
CoreData: many-to-many relationship
Answer is found ... i tried to use property of the autogenerated entities when created new records in CoreData, in the meantime the correct way is to use generated methods like - addPointLinkObject, addEntityLinkObject, etc
Example, i have 3 tables :
Contacts (one person may have many locations)
<< - >>
Points (one location can contain many people)
<< - >
EntityTypes (just a type of a location, in this case type is CONTACT)
One of the entities autogenerated by xCode :
#interface PointEntity : Entity
#property (nonatomic, retain) NSNumber *latitude;
#property (nonatomic, retain) NSNumber *longitude;
#property (nonatomic, retain) NSSet *entityLink; // reference to Contacts table (ManyToMany)
#property (nonatomic, retain) EntityEntity *entityTypeLink; // reference to EntityType table (OneToMany)
#end
#interface PointEntity (CoreDataGeneratedAccessors)
- (void)addEntityLinkObject:(ContactEntity *)value;
- (void)removeEntityLinkObject:(ContactEntity *)value;
- (void)addEntityLink:(NSSet *)values;
- (void)removeEntityLink:(NSSet *)values;
#end
I tried to do the following :
// create 3 new instances - one for each entity
ContactEntity *contactEntity = [model create:model];
PointEntity *pointEntity = [point create:point];
EntityModel *entity = [[[EntityModel alloc] init] autorelease];
entity.name = model.table;
EntityEntity *entityEntity = [[entity list:entity] objectAtIndex:0];
// then i tried to use entity's properties directly to bind entities
// it works, but it works only on DB level when we add new records, but somehow something was missed and thus such selection did not work later - [pointEntity allObjects]
//pointEntity.entityTypeLink = entityEntity; // WRONG !!!
//pointEntity.entityLink = contactEntity.pointLink;
//contactEntity.pointLink = pointEntity.entityLink;
// then i replaced 3 lines above with these ones
[pointEntity addEntityLinkObject:contactEntity]; // CORRECT !!!
[contactEntity addPointLinkObject:pointEntity];
[entityEntity addPointLinkObject:pointEntity];
[context save]; // save changes made with entities in current CoreData context
// now [pointEntity allObjects] and [pointEntity anyObject] work as expected
Useful links -
Coredata and Generated subclass for NSManagedObject with relations
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdAccessorMethods.html#//apple_ref/doc/uid/TP40002154
Related
I'm trying to get data by using core data,but something wrong happen.Here's the picture of my data model:
And code of Feed.h
#interface Feed (CoreDataProperties)
#property (nullable, nonatomic, retain) NSString *rssURL;
#property (nullable, nonatomic, retain) NSString *summary;
#property (nullable, nonatomic, retain) NSString *title;
#property (nullable, nonatomic, retain) NSSet *feedItems;
#end
Firstly,I'm sure I get the data of Feed Table in My FeedList TableViewController.When I tap one row of the table,it should push to the FeedItem TableViewController which contains the data of FeedItem.Here's the code of First Controller:
- (void)cellDidPress:(NSIndexPath *)atIndexPath{
if (atIndexPath.row < self.allFeeds.count) {
RSFeedItemsViewController *itemsVC = [[RSFeedItemsViewController alloc] init];
itemsVC.feed = self.allFeeds[atIndexPath.row];
[self.navigationController pushViewController:itemsVC animated:YES];
}
}
I try to get the FeedItem in my FeedItemsViewController
NSMutableArray *allItems = [[[self.feed feedItems] allObjects] mutableCopy];
And I'm getting the following exception:
po [self.feed feedItems]
<FeedItem: 0x7fe95a484540> (entity: FeedItem; id: 0xd000000007f40002 <x-coredata://918D3499-5129-4D78-8F37-3D8D478FE482/FeedItem/p509> ; data: <fault>)
2016-07-10 14:17:33.176 RSFeedReader[98980:14910776] -[FeedItem allObjects]: unrecognized selector sent to instance 0x7fe95a484540
Should I execute another fetch request to get the data of FeedItem?
Any help is appreciated.
Thanks
I've two classes like this,
#class Songs;
#interface Album : NSManagedObject
#property (nonatomic, retain) NSNumber * albumID;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *songs;
#end
#interface Album (CoreDataGeneratedAccessors)
- (void)addSongsObject:(Songs *)value;
- (void)removeSongsObject:(Songs *)value;
- (void)addSongs:(NSSet *)values;
- (void)removeSongs:(NSSet *)values;
#end
#class Album;
#interface Songs : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSNumber * length;
#property (nonatomic, retain) Album *owner;
#end
Suppose, I've 10 albums created and each album have some random (positive) number of songs. Now I want to find & fetch top 5 albums which has the maximum number of songs.
How do I do that with MagicalRecords?
Currently, I'm doing it like this,
NSLog(#"%#",[Album MR_findAllSortedBy:#"albumID" ascending:YES withPredicate:[NSPredicate predicateWithFormat:#"#max.#count.songs"]]);
//NSLog(#"%#",[Album MR_findAllSortedBy:#"albumID" ascending:YES]); //works fine
but its crashes with following message:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format
string "#max.#count.songs"'
Is my predicate string invalid? If yes, what is the correct way to achieve this.
According to this post, you can not sort by count on fetch. You need to fetch all items and than sort and trim them:
NSArray* array = [Album MR_findAll];
array = [array sortedArrayUsingDescriptors:#[ [NSSortDescriptor sortDescriptorWithKey:#"songs.#count" ascending:NO] ] ];
array = [array subarrayWithRange:NSMakeRange(0, MIN( array.count, 5) )];
I have a coredata project with the following entities:
I'm trying to get the list of the content base on the category:
here is my coredata clasess .h:
#interface Content : NSManagedObject
#property (nonatomic, retain) NSString * contenido;
#property (nonatomic, retain) NSNumber * index;
#property (nonatomic, retain) NSString * titulo;
#property (nonatomic, retain) NSNumber * uploadCloudKit;
#property (nonatomic, retain) Categories *category;
---
#class Content;
#interface Categories : NSManagedObject
#property (nonatomic, retain) NSString * categoryName;
#property (nonatomic, retain) NSSet *content;
#end
NSEntityDescription *categoryDescription = [ NSEntityDescription entityForName:#"Categories" inManagedObjectContext:moc];
NSFetchRequest *categoRequest = [NSFetchRequest new];
categoRequest.entity = categoryDescription;
NSPredicate *categoPredicate = [NSPredicate predicateWithFormat:#"categoryName like %#", category];
categoRequest.predicate = categoPredicate;
NSArray *results = [moc executeFetchRequest:categoRequest error:&error];
but when I try to access the content on the result for the category I get:
po [results valueForKey:#"content"]
<__NSArrayI 0x6080000243a0>(
Relationship 'content' fault on managed object (0x6080000a2220) <Categories: 0x6080000a2220> (entity: Categories; id: 0x40002b <x-coredata://FDBA3FB2-F1F8-498E-9071-3A5D1ABE66F0/Categories/p1> ; data: {
categoryName = movies;
content = "<relationship fault: 0x610000030fa0 'content'>";
})
)
Any of you knows how can I get the content items of the result?
I'll really appreciate your help
It's a normal behaviour for CoreData. You should read Apple Documentation. There you can read about fault objects for CoreData. In two words - fault means that CoreData has this object but know (for some reason CoreData won't print you all fields of the object).
In order to see all vields you should do this:
[categoRequest setReturnsObjectsAsFaults:NO];
But I recomend you to do this only for debug, because CoreData smarter and know what to do with memory managment)
I am having Country, State and City entities in my CoreData model. Here is the structure:
#interface Country : NSManagedObject
#property (nonatomic, retain) NSString * cId;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSSet *states; // This will contain State object
#end
#interface State : NSManagedObject
#property (nonatomic, retain) NSString * sId;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSSet *cities; // This will contain City object
#property (nonatomic, retain) Country *country;
#end
#interface City : NSManagedObject
#property (nonatomic, retain) NSString * cityId;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) State *state;
#end
As you can see I have one to many relation between Country - State and State - City.
Now what I want is to fetch Country list with all states, but don't want city list associated with States.
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Country"];
[request setPropertiesToFetch:#[#"cId", #"title", #"states"]];
NSError *error = nil;
NSArray *aryCategories = [gblAppDelegate.managedObjectContext executeFetchRequest:request error:&error];
setPropertiesToFetch Setting this property allows to have only mentioned fields from the entity but how to set only sid and title for NSSet states which contain State object.
For getting city list I will send another request.
Please help me on this.
You do not need propertiesToFetch. This feature (which BTW needs the NSDictionaryResultType) is for special situations where you have lots of data and only need certain fields. This is definitely not necessary in your case!
Just fetch the Country objects. Core Data will automatically optimize to avoid fetching unnecessary data into memory.
NSFetchRequest *request = [NSFetchRequest fetchRequestsWithEntityName:#"Country"];
// consider sorting
NSArray *countryList = [context executeFetchRequest:request error:nil];
You now have a country list. It contains also the states. To get the states of a particular country could not be simpler.
NSSet *states = country.states;
NB: I think calling your to-one relationship from City to State "country" is problematic. I suggest renaming it to state.
I am having two classes or objects: User and Medicine. Here is my User class:
#interface User : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *medicine;
#end
#interface User (CoreDataGeneratedAccessors)
- (void)addMedicineObject:(Medicine *)value;
- (void)removeMedicineObject:(Medicine *)value;
- (void)addMedicine:(NSSet *)values;
- (void)removeMedicine:(NSSet *)values;
#end
and then the Medicine class
#interface Medicine : NSManagedObject
#property (nonatomic, retain) NSString * medName;
#property (nonatomic, retain) NSString * medType;
#property (nonatomic, retain) Dose *dose;
#property (nonatomic, retain) User *user;
#end
As my interfaces clearly show that user may have multiple medicines. (I am from database background thats why I am interpreting it like this).
When I add new object in User, it is easily done, but when I try to add new Medicine for existing object of user, I feel that my Xcode has a deep wish to shoot me at that time (vice versa).
Now here is the code that describes what I am doing:
Medicine *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
User *user = [NSEntityDescription insertNewObjectForEntityForName:#"User" inManagedObjectContext:self.managedObjectContext];
if(![self checkUser])
{
object.user = user;
[user setName:self.userName];
NSLog(#"%# %#",object, user);
self.detailViewController.detailItem = object;
}
else
{
Medicine *medicine = [NSEntityDescription insertNewObjectForEntityForName:#"Medicine" inManagedObjectContext:self.managedObjectContext];
user = [self getUser:self.userName];
medicine.medName = object.medName;
medicine.medType = object.medType;
[medicine setUser:user];
self.detailViewController.detailItem = medicine;
}
I am having a simple logic: if name entered by user in text field, already exist in DB, then return the User object. Then just add another Medicine record for the same User. Other wise add new User and a Medicine object as well.
but I get error at:
[medicine setUser:user];
I also tried this one: (as I got it in another question like mine)
[user addMedicineObject:medicine];
Now I think that I have to override addMedicineObject method or something else.
Oh I forgot the error. I get this error: (the real villain)
[__NSArrayM managedObjectContext]: unrecognized selector sent to instance 0x8136bf0
Now any suggestion?
It is because you trying to mutate NSSet object. You need to create a mutable copy before you edit it.