Problème CoreData

antoine2405antoine2405 Membre
août 2009 modifié dans API AppKit #1
Bonjour,

J'ai un probléme au niveau de CoreData.


Voici mon schéma.

http://www.flickr.com/photos/mayous/3817738830/

Donc j'ai deux entité, "profil", "sauvegarde".

Un profil a plusieurs sauvegarde.

Sachant que chaque sauvegarde à  une date, j'aimerai afficher dans un formulaire les dernière sauvegarde fait par utilisateurs.

Il faut savoir aussi que je stock dans la base de donnée chaque sauvegarde fait par un utilisateur

J'envisagait d'utiliser un predicate de max(date) mais se ne marche pas du tout ...

Avez vous une idée?


Merci d'avance

Réponses

  • Philippe49Philippe49 Membre
    22:03 modifié #2
    Tu as regardé du côté des NSFetchRequest , avec des NSPredicate effectivement ? exemple
  • antoine2405antoine2405 Membre
    22:03 modifié #3
    Ouai oaui, j'ai regardé... mais j'avais vue qu'il y avait la possibilité d'utiliser les expression.

    Par contre je ne vois pas comment il marche...
  • Philippe49Philippe49 Membre
    22:03 modifié #4
    Predicate Programming Guide
    C'est sur que NSPredicate pour signifier "les 10 dernières dates", cela demande réflexion. Bien sur il y a toujours la solution de tout récupérer en une NSArray pour trier après.
  • antoine2405antoine2405 Membre
    22:03 modifié #5
    tu dis ca ironiquement ?
  • Philippe49Philippe49 Membre
    22:03 modifié #6
    Pas du tout. Comme tu dis plus haut, on a MAX, on a '>' . Mais dire les 10 derniers en un seul predicate ? Les 2 ou 3 derniers peut-être.
    Paresseusement, je regrouperais les entities dans une NSArray, puis un tri sortedArrayUsing..
  • antoine2405antoine2405 Membre
    22:03 modifié #7
    arf désoler, je pris ta réponse autrement ^^.

    Bref je suis plus partie sur un tripe un peu comme ca.
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; <br />	NSEntityDescription *entity = [NSEntityDescription entityForName:@&quot;Sauvegarde&quot; inManagedObjectContext:managedObjectContext]; <br />	<br />	<br />	[request setEntity:entity]; <br />	[request setPredicate:predicate];<br />	<br />	NSError *error = nil;<br />	NSArray *array = [managedObjectContext executeFetchRequest:request error:&amp;error];<br />	if (array == nil)<br />	{<br />&nbsp; &nbsp; // Deal with error...<br />	}<br /><br />	NSDate *tempDate = 0;<br />	NSManagedObjectID *num ;	<br />	NSUInteger i, count = [array count];<br />for (i = 0; i &lt; count; i++) {<br />	//NSObject * obj = [array	objectAtIndex:i];<br />	sauvegarde	= (Sauvegarde *) [array objectAtIndex:i];<br /><br />	if ([sauvegarde date] &gt; tempDate)<br />	{		<br />		tempDate = [sauvegarde date];<br />		<br />		}<br />	<br />	num	= [sauvegarde objectID];<br />}<br />	<br />		[num entity];
    



    Bon maintenant je suis un peu perdu ^^ mais bon je vais bien trouver...
  • AliGatorAliGator Membre, Modérateur
    22:03 modifié #8
    Tiens, ça m'étonne que dans NSPredicate on ait pas la possibilité de demander MAX ou des trucs comme ça ? Un peu limitatif ça :(

    Sinon pour info antoine :
    1) Quand tu peux, utilise les boucles de type NSFastEnumeration plutôt que les boucles for "à  index" pour parcourir les collections genre NSArray : c'est plus rapide
    for(sauvegarde in array)<br />{<br />&nbsp; if ([sauvegarde date] &gt; tempDate) tempDate = [sauvegarde date];<br />}
    


    2) Maintenant, je me demande si avec un KeyPath on ne peut pas demander directement l'objet ayant la date max ? un KP genre "date.@max"; justement...?
  • Philippe49Philippe49 Membre
    août 2009 modifié #9
    dans 1250584107:

    2) Maintenant, je me demande si avec un KeyPath on ne peut pas demander directement l'objet ayant la date max ? un KP genre "date.@max"; justement...?

    Si pour le MAX, y a pas de problème, mais ici il faut les 10 derniers de la liste.


    Pour sortedArray, voici un exemple :
    <br />#import &lt;Foundation/Foundation.h&gt;<br /><br />@interface Toto : NSObject {<br />	NSDate * date;<br />	NSString * name;<br />}<br />@property (nonatomic,retain) 	NSDate * date;<br />@property (nonatomic,retain) 	NSString * name;<br />-(NSComparisonResult) compare:(Toto *) obj;<br />@end<br /><br />@implementation Toto<br />@synthesize date,name;<br />-(NSComparisonResult) compare:(Toto *) obj {<br />	NSComparisonResult dateComparison=[self.date compare:obj.date];<br />	if(dateComparison!=NSOrderedSame) {<br />		return dateComparison;<br />	} <br />	return [self.name compare:obj.name];<br />}<br />-(NSString *) description {<br />	return [NSString stringWithFormat:@&quot;%@ &#092;t&#092;tdate : %@&quot;,name,date];<br />}<br />@end<br /><br />#define ARRAY_COUNT 20<br /><br />int main (int argc, const char * argv&#91;]) {<br />	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];<br />	NSMutableArray * array=[NSMutableArray array];<br />	NSDate * date=[NSDate date];<br />	for(NSUInteger i=0;i&lt;ARRAY_COUNT;i++) {<br />		Toto * a=[[[Toto alloc] init] autorelease]; <br />		a.date=[date addTimeInterval:(3*i)%7]; <br />		a.name=[NSString stringWithFormat:@&quot;Toto %lu&quot;,i];<br />		[array addObject:a];<br />	}<br />	NSArray * sortedArray=[array sortedArrayUsingSelector:@selector(compare:)];<br />	NSLog(@&quot;%@&quot;,sortedArray);<br />	[pool drain];<br />	return 0;<br />}<br /><br />
    



    % gcc pgm.m -o pgm -std=c99 -framework Foundation
    % pgm
    2009-08-18 10:36:48.344 pgm[498:10b] (
        Toto 0 date : 2009-08-18 10:36:48 +0200,
        Toto 14 date : 2009-08-18 10:36:48 +0200,
        Toto 7 date : 2009-08-18 10:36:48 +0200,
        Toto 12 date : 2009-08-18 10:36:49 +0200,
        Toto 19 date : 2009-08-18 10:36:49 +0200,
        Toto 5 date : 2009-08-18 10:36:49 +0200,
        Toto 10 date : 2009-08-18 10:36:50 +0200,
        Toto 17 date : 2009-08-18 10:36:50 +0200,
        Toto 3 date : 2009-08-18 10:36:50 +0200,
        Toto 1 date : 2009-08-18 10:36:51 +0200,
        Toto 15 date : 2009-08-18 10:36:51 +0200,
        Toto 8 date : 2009-08-18 10:36:51 +0200,
        Toto 13 date : 2009-08-18 10:36:52 +0200,
        Toto 6 date : 2009-08-18 10:36:52 +0200,
        Toto 11 date : 2009-08-18 10:36:53 +0200,
        Toto 18 date : 2009-08-18 10:36:53 +0200,
        Toto 4 date : 2009-08-18 10:36:53 +0200,
        Toto 16 date : 2009-08-18 10:36:54 +0200,
        Toto 2 date : 2009-08-18 10:36:54 +0200,
        Toto 9 date : 2009-08-18 10:36:54 +0200
    )
    %
  • antoine2405antoine2405 Membre
    22:03 modifié #10
    J'ai trouvé une solution...

    Elle est pas du tout optimiser mais ca marche pour l'instant ^^

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; <br />	NSEntityDescription *entity = [NSEntityDescription entityForName:@&quot;Sauvegarde&quot; inManagedObjectContext:managedObjectContext]; <br />	<br />	<br />	[request setEntity:entity]; <br />	<br />	<br />	NSError *error = nil;<br />	NSArray *array = [managedObjectContext executeFetchRequest:request error:&amp;error];<br />	if (array == nil)<br />	{<br />&nbsp; &nbsp; // Deal with error...<br />	}<br /><br />	NSDate *tempDate = 0;<br />	NSManagedObjectID *num ;	<br />	NSUInteger i, count = [array count];<br />for (i = 0; i &lt; count; i++) {<br /><br />Sauvegarde	*tempsauvegarde	= (Sauvegarde *) [array objectAtIndex:i];<br /><br />	if ([tempsauvegarde date] &gt; tempDate)<br />	{		<br />		tempDate = [tempsauvegarde date];<br />		<br />		}<br />	<br />	num	= [tempsauvegarde objectID];<br />	<br />}<br /><br />	<br />	sauvegarde	= (Sauvegarde *) [managedObjectContext objectWithID:num];
    



    Alors merci AliGator pour le conseil...

    En faite il y a la possibilité d'utiliser MAX mais il faut être dans une expressions et je ne savais pas trop comment m'y prendre.

    petit link pour information :
    http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSExpression_Class/Reference/NSExpression.html

    c'est au niveau de expressionForFunction:arguments:


    J'ai pas encore tout piger le principe au niveau des KeyPath.. pas encore l'habitude...

    Bon Maintenant il faut que j'arrive a dire a ma requête de faire la liaison avec un "Profil".. parce qu'il me prend toutes les données qui sont présentes dans sauvegarde. Encore une question de ID quelque chose...

    Je vais regardé ca de plus prés...

    Si vous avez idée, je suis preneur hiii hiii ^^

    Merci encore
  • AliGatorAliGator Membre, Modérateur
    22:03 modifié #11
    En effet, pas bête... Me disait bien que ça me semblait étrange que ça ne soit pas possible...

    Du coup pour avoir la sauvegarde qui a la plus grande (récente) date -- pour reprendre mon questionnement juste du "max" -- si tu construis une NSExpression avec le keyPath @date.@max";, puis un NSPredicate utilisant cette NSExpression, tu devrais t'en sortir.

    Maintenant, pour récupérer juste les 10 dernières, par contre, là ...
    En SQL, je demanderais dans ma requête de trier les résultats par date décroissante, et limiterait le nombre de résultats à  10. En CoreData avec les NSPredicate, est-ce possible un truc comme ça...?
  • antoine2405antoine2405 Membre
    22:03 modifié #12
    Oaui c'est trés simple de limité le nombre de résultat.

    Il suffit d'utiliser un fetchLimit sur ta request donc aprés si tu en veux 10

    ca devient:

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; <br />	NSEntityDescription *entity = [NSEntityDescription entityForName:@&quot;Sauvegarde&quot; inManagedObjectContext:managedObjectContext]; <br />	NSPredicate *predicate = [NSPredicate predicateWithFormat:@&quot;profil == %@&quot;,];<br />	[request fetchLimit:10];<br />....
    


    Une petite idée pour faire la liaison avec la table profil ?

    Par contre dans mon cas, je n'ai aucune envie de limité les résultats parce que dans le futur je vais en avoir besoin pour un graphique...



    En passant si vous vous y connaissez en graphique avec l'iphone, j'aimerai bien des informations parce que je sens que je vais avoir mal ...

  • Philippe49Philippe49 Membre
    22:03 modifié #13
    dans 1250591465:

    Oaui c'est trés simple de limité le nombre de résultat.

    Il suffit d'utiliser un fetchLimit sur ta request donc aprés si tu en veux 10

    ca devient:

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; <br />	NSEntityDescription *entity = [NSEntityDescription entityForName:@&quot;Sauvegarde&quot; inManagedObjectContext:managedObjectContext]; <br />	NSPredicate *predicate = [NSPredicate predicateWithFormat:@&quot;profil == %@&quot;,];<br />	[request fetchLimit:10];<br />....
    


    Oui enfin cela ne doit pas filtrer pas les 10 dates maximales, mais limiter le nombre de résultats à  dix objets.
  • Philippe49Philippe49 Membre
    22:03 modifié #14
    Pour obtenir les objets correspondant au max, je n'ai pas trouvé mieux pour l'instant que :

    <br />int main (int argc, const char * argv&#91;]) {<br />	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];<br />	// creating array<br />	NSMutableArray * array=[NSMutableArray array];<br />	NSDate * date=[NSDate date];<br />	for(NSUInteger i=0;i&lt;ARRAY_COUNT;i++) {<br />		Toto * a=[[Toto alloc] init]; <br />		a.date=[date addTimeInterval:(3*i)%7]; <br />		a.name=[NSString stringWithFormat:@&quot;Toto %lu&quot;,i];<br />		[array addObject:a];<br />	}<br />//	NSArray * sortedArray=[array sortedArrayUsingSelector:@selector(compare:)];<br />	<br />	<br />	NSDate * dateMax=[array valueForKeyPath:@&quot;@max.date&quot;];<br />	NSPredicate * predicate=[NSPredicate predicateWithFormat:@&quot;SELF.date =%@&quot;,dateMax];<br />	NSArray * filteredArray=[array filteredArrayUsingPredicate:predicate];<br />	NSLog(@&quot;%@&quot;,filteredArray);<br />	[pool drain];<br />	return 0;<br />}<br />
    


    (NSArray * filteredArray=[array filteredArrayUsingPredicate:predicate]; à  traduire en NSFetchRequest )
  • Philippe49Philippe49 Membre
    août 2009 modifié #15
    dans 1250591465:

    Une petite idée pour faire la liaison avec la table profil ?

    CoreData met en place un NSPersistentStoreCoordinator en intermédiaire avec la base de donnée. Il faut donc passer par les classe de CoreData pour "dialoguer" avec la bdd.


    dans 1250591465:

    En passant si vous vous y connaissez en graphique avec l'iphone, j'aimerai bien des informations parce que je sens que je vais avoir mal ...

    Ce forum présente une rubrique pour cela.
  • antoine2405antoine2405 Membre
    22:03 modifié #16
    J'ai enfin fini se que je voulais.

    Voici le code :
    profil = (Profil *)[eventsArray objectAtIndex:self.selectedRow];<br /><br />	NSNumber&nbsp; *numPosition = [NSNumber numberWithInt:self.selectedRow +1];<br />	<br />	NSFetchRequest *request = [[NSFetchRequest alloc] init]; <br />	NSEntityDescription *entity = [NSEntityDescription entityForName:@&quot;Sauvegarde&quot; inManagedObjectContext:managedObjectContext]; <br />	NSPredicate *predicate = [NSPredicate predicateWithFormat:@&quot;profil == %@&quot;,numPosition];<br /><br />	[request setPredicate:predicate];<br />	[request setEntity:entity]; <br />	<br />	<br />	NSError *error = nil;<br />	NSArray *array = [managedObjectContext executeFetchRequest:request error:&amp;error];<br />	if (array == nil)<br />	{<br />&nbsp; &nbsp; // Deal with error...<br />	}<br /><br />	NSDate *tempDate = 0;<br />	NSManagedObjectID *num ;	<br />	NSUInteger i, count = [array count];<br />for (i = 0; i &lt; count; i++) {<br /><br />Sauvegarde	*tempsauvegarde	= (Sauvegarde *) [array objectAtIndex:i];<br /><br />	if ([tempsauvegarde date] &gt; tempDate)<br />	{		<br />		tempDate = [tempsauvegarde date];<br />		<br />		}<br />	<br />	num	= [tempsauvegarde objectID];<br />	<br />}<br /><br />	<br />	sauvegarde	= (Sauvegarde *) [managedObjectContext objectWithID:num];<br />	<br />
    


    Ca marche pour l'instant.

    Merci les mecs pour l'aide ^^
  • AliGatorAliGator Membre, Modérateur
    22:03 modifié #17
    Pourquoi (1) ne pas utiliser les FastEnumeration comme je te le suggérais plus haut pour optimiser ta boucle (2) stocker directement le Sauvegarde* quand tu le trouves, plutôt que de stocker le num à  la place, et rerécupérer le Sauvegarde* ensuite ?

    Sauvegarde* foundSauv = [array objectAtIndex:0];<br />for (Sauvegarde* tempSauv in array)<br />{<br />&nbsp;  if ([tempSauv date] &gt; [foundSauv date])<br />&nbsp;  {&nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; foundSauv = tempSauv;<br />&nbsp; &nbsp; }<br />}
    


    Mais bon, de même, pourquoi plutôt qu'une boucle ne pas faire [tt][array valueForKeyPath:@date.@max";][/tt] ? (pas testé mais je vois pas pourquoi ça marcherait pas)
  • antoine2405antoine2405 Membre
    22:03 modifié #18
    Ca marche pas pour moi le
    [array valueForKeyPath:@&quot;date.@max&quot;]
    


    Par contre merci pour l'autre partie de code, c'est beaucoup plus proche et j'y avais même pas penser ^^

    Sa Rocks


Connectez-vous ou Inscrivez-vous pour répondre.