Reputation: 5001
I have a Core Data with Song, Artist and Album entity.
Song have an optional one to one relationship artist to the Artist entity and album to Album entity Both entity has an inverse relationship to the Song entity.
Album have an optional one to one relationship artist to the Artist entity and an optional one to many relationship songs to Song entity
Both entity has an inverse relationship to the Album entity.
Artist have an optional one to one relationship album to the Album entity and an optional one to many relationship songs to Song entity Both entity has an inverse relationship to the Artist entity.
I would like to fetch distinct artist name and started to do this
NSArray *getAllArtistArray = [Song findBy:nil orderBy:@"songName asc"]; // fetch all songs in Song entity
then i loop them to find unique artist name
for(Song *songItem in getAllArtistArray)
{
BOOL hasDuplicate = [[uniqueArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"%K == %@",@"artist.artistName", songItem.artist.artistName]] count] > 0;
if (!hasDuplicate)//if uniqueArray found artistname, don add songItem
{
[uniqueArray addObject:songItem];
}
}
here is the problem :/
I need to find the Song and Album count of individual artist.
//fixed Indention
//this works for finding the song count of individual Artist but is this the right way ?
-(int)searchSongItemCountInSongbasedOnArtist:(NSString *)searchStr //song count of artist
{
NSPredicate *getSearchPred = [NSPredicate predicateWithFormat:@"%K == %@", @"artist.artistName", searchStr];
NSArray *countArray = [Song findBy:getSearchPred orderBy:@"artist.artistName asc"];
[self searchAlbumCountBasedOnArtist:searchStr andSongArray:countArray];
return [countArray count];
}
how to i find the album count of individual based on the artist name ? MPMediaQuery can easily do it, how i can do it using NSPredicate with coredata ?
-(int)searchAlbumCountBasedOnArtist:(NSString *)searchStr andSongArray:(NSArray *)songArray
{
MPMediaQuery *albumQuery = [MPMediaQuery albumsQuery];
NSArray *albumCollection = [albumQuery collections];
[albumQuery addFilterPredicate: [MPMediaPropertyPredicate predicateWithValue:searchStr
forProperty:MPMediaItemPropertyArtist]];
return [albumCollection count];
}
Album
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Artist, Song;
@interface Album : NSManagedObject
@property (nonatomic, retain) NSNumber * albumID;
@property (nonatomic, retain) NSString * albumTitle;
@property (nonatomic, retain) NSString * albumTitleEN;
@property (nonatomic, retain) NSSet *artists;
@property (nonatomic, retain) NSSet *songs;
@end
@interface Album (CoreDataGeneratedAccessors)
- (void)addArtistsObject:(Artist *)value;
- (void)removeArtistsObject:(Artist *)value;
- (void)addArtists:(NSSet *)values;
- (void)removeArtists:(NSSet *)values;
- (void)addSongsObject:(Song *)value;
- (void)removeSongsObject:(Song *)value;
- (void)addSongs:(NSSet *)values;
- (void)removeSongs:(NSSet *)values;
@end
Song
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Album, Artist;
@interface Song : NSManagedObject
@property (nonatomic, retain) NSNumber * acousticness;
@property (nonatomic, retain) NSNumber * danceability;
@property (nonatomic, retain) NSString * deleted;
@property (nonatomic, retain) NSNumber * durationEN;
@property (nonatomic, retain) NSNumber * energy;
@property (nonatomic, retain) NSString * genre;
@property (nonatomic, retain) NSNumber * key;
@property (nonatomic, retain) NSNumber * liveness;
@property (nonatomic, retain) NSNumber * loudness;
@property (nonatomic, retain) NSString * md5Hash;
@property (nonatomic, retain) NSNumber * mode;
@property (nonatomic, retain) NSNumber * mood;
@property (nonatomic, retain) NSNumber * pID;
@property (nonatomic, retain) NSNumber * playbackDuration;
@property (nonatomic, retain) NSString * serverID;
@property (nonatomic, retain) NSString * songName;
@property (nonatomic, retain) NSString * songNameEN;
@property (nonatomic, retain) NSString * songURL;
@property (nonatomic, retain) NSNumber * speechiness;
@property (nonatomic, retain) NSNumber * tempo;
@property (nonatomic, retain) NSNumber * valance;
@property (nonatomic, retain) Album *albums;
@property (nonatomic, retain) Artist *artists;
@end
Artist
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Album, Song;
@interface Artist : NSManagedObject
@property (nonatomic, retain) NSNumber * artistID;
@property (nonatomic, retain) NSString * artistIDEN;
@property (nonatomic, retain) NSString * artistName;
@property (nonatomic, retain) NSString * artistNameEN;
@property (nonatomic, retain) NSSet *albums;
@property (nonatomic, retain) NSSet *songs;
@end
@interface Artist (CoreDataGeneratedAccessors)
- (void)addAlbumsObject:(Album *)value;
- (void)removeAlbumsObject:(Album *)value;
- (void)addAlbums:(NSSet *)values;
- (void)removeAlbums:(NSSet *)values;
- (void)addSongsObject:(Song *)value;
- (void)removeSongsObject:(Song *)value;
- (void)addSongs:(NSSet *)values;
- (void)removeSongs:(NSSet *)values;
@end
Any comments / answers are greatly appreciated!
Upvotes: 0
Views: 1169
Reputation: 8988
Firstly let me point out that I have no knowledge of the library you are using (VPPCoreData or whatever) - I try and avoid anything that seems to make things simpler because invariably there is a tradeoff somewhere.
Secondly - trying to figure out the code where things get added and relationships get set.
Songs
get created and the album
is assigned with this code (note albums
and artists
are To-One relationships and should be renamed to singular album
and artist
to avoid confusion with a To-Many relationship)
song.albums = [self findOrCreateAlbumFromMediaItem:mediaItem];
song.artists = [self findOrCreateArtistFromMediaItem:mediaItem];
I assume that a song exists in only one Album
and a song has but one Artist
.
Now you don't set any relationships between the Artist
and the Album
which is why it always comes up ZERO. And its probably better not to because you can get this relationship from the artist.songs
relationship.
So you have two choices, 1) determine the albums based on the songs that are related to the artist and don't maintain a artist.albums or albums.artists relationship, or 2) set the album.artists relationship yourself and use that.
For 1) You need to do this
// Get the array of Albums
NSArray *list = [artist.songs valueForKeyPath:@"@distinctUnionOfObjects.album"];
NSLog(@" album count is %d", list.count);
for (Album *album in list) {
NSLog(@" album is %@", album.albumTitle);
}
For 2) it means maintain duplicate information and the risk that something gets out of sync, but it could be easier to simply set the relationship when getting the album and artist. If anything changes you have to change the relationships too.
song.album = [self findOrCreateAlbumFromMediaItem:mediaItem];
song.artist = [self findOrCreateArtistFromMediaItem:mediaItem];
NSMutableSet *albumArtists = [song.album mutableSetValueForKey:@"artists"];
[albumArtists addObject:song.artist];
You could add a read only property to the Artist object like this
in Artist.h
@property (readonly) NSArray *albumList;
in Artists.m
- (NSArray *)albumList {
return [artist.songs valueForKeyPath:@"@distinctUnionOfObjects.album"];
}
Then you can just do the following to get the count
albumCount = [[artist albumList] count];
or perhaps dot notation will work
albumCount = artist.albumList.count;
Upvotes: 1
Reputation: 8988
Fetch the artist and then use artist.albums.count
.
This assumes you have a To-Many relationship between Artist
and Album
called albums
and another between Artists
and Song
called songs
.
Similarly you could use artist.songs.count
to get the number of songs
Here is a generic method to fetch an array of entities
- (NSArray *)getData:(NSString*)entityName sortField:(NSString*)sortKey predicate:(NSPredicate*)predicate managedObjectContext:(NSManagedObjectContext*)managedObjectContext
{
NSLog(@"getData called");
if (managedObjectContext == nil) {
NSLog(@"Error can't continue with null managedObjectContext");
return nil;
}
if (entityName == nil) {
NSLog(@"Error can't continue with null entityName");
return nil;
}
if (sortKey == nil) { // if its not set then just set it as follows...
NSLog(@"Error can't continue with null sortField");
return nil;
}
NSLog(@" entity is %@", entityName);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
if (entity == nil) {
NSLog(@" error finding entity %@ in class %@", entityName, [self class]);
return nil;
}
[fetchRequest setEntity:entity];
if (predicate)
[fetchRequest setPredicate:predicate];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:YES];
NSArray *sortDescriptors =[NSArray arrayWithObjects:sortDescriptor,nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (!result) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
return nil;
}
return result;
}
Then to get the album and song counts
- (void)listAllMethod {
NSArray *artists = [self getData:@"Artists" sortField:@"artistName" predicate:nil managedObjectContext:self.managedObjectContext;
for (Artist *artist in artists) {
NSLog(@" artist is %@", artist.artistName);
NSLog(@" album count is %d", [artist.albums.count intValue]);
NSLog(@" song count is %d", [artist.songs.count intValue]);
for (Album *album in artist.albums)
NSLog(@" album is %@", album.albumTitle);
for (Song *song in artist.songs)
NSLog(@" song is %@", song.songName);
}
NSArray *albums = [self getData:@"Albums" sortField:@"albumTitle" predicate:nil managedObjectContext:self.managedObjectContext;
for (Album *album in albums) {
NSLog(@" album is %@", album.albumTitle);
NSLog(@" artist count is %d", [album.artists.count intValue]);
for (Artist *artist in albums.artists)
NSLog(@" artist is %@", artist.artistName);
}
}
Upvotes: 2