retourner l'ID (primaryKey) d'une entité

antoine2405antoine2405 Membre
septembre 2009 modifié dans API AppKit #1
Bonsoir,

J'essaie de retourner l'ID de ma table "Profil" qui est stocké dans une base de donnée SQLite.

J'ai donc créer une methode idUsers... :

-(NSMutableArray *)idUsers{<br />	<br />	<br />	profil = (Profil *)[eventsArray objectAtIndex:self.selectedRow];<br />	//NSNumber&nbsp; *numPosition = [NSNumber numberWithInt:self.selectedRow +1];<br /><br /><br />	NSString *nomPre = [[NSString alloc]initWithFormat:@&quot;%@&quot;,[profil nom] ];<br /> 	NSString *prenPre = [[NSString alloc]initWithFormat:@&quot;%@&quot;,[profil prenom] ];<br />	<br />	NSFetchRequest *request = [[NSFetchRequest alloc] init]; <br />	NSEntityDescription *entitySauv = [NSEntityDescription entityForName:@&quot;Profil&quot; inManagedObjectContext:managedObjectContext]; <br />	NSPredicate *predicate = [NSPredicate predicateWithFormat:@&quot;(nom == %@) AND (prenom == %@)&quot;,nomPre, prenPre];<br /><br />	[request setPredicate:predicate];<br />	[request setEntity:entitySauv]; <br />	[request setResultType:NSManagedObjectIDResultType];<br />	<br />	<br />	NSError *error = nil;<br /><br />	NSMutableArray *arrayIdProfil = [[managedObjectContext executeFetchRequest:request error:&amp;error] mutableCopy];<br />				<br />	if (arrayIdProfil == nil)<br />	{<br />		// Deal with error...<br />	}<br />	<br /><br />	<br />	<br />	NSManagedObjectID* objectID = [arrayIdProfil lastObject];<br />	<br />	NSManagedObject* object	= [managedObjectContext objectWithID:objectID];<br />	<br />	NSLog(@&quot;COUCOUC %@&quot;,[object objectID]);<br />	<br />	NSLog(@&quot;COUCOUC %@&quot;,object);<br />	<br />	NSLog(@&quot;COUCOUC %@&quot;,[object entity]);<br />	<br />	NSFetchRequest *request2 = [[NSFetchRequest alloc] init]; <br />	NSEntityDescription *entitySauv2 = [NSEntityDescription entityForName:@&quot;Sauvegarde&quot; inManagedObjectContext:managedObjectContext]; <br />	NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@&quot;profil == &quot;,&nbsp; ];<br />	<br />	[request2 setPredicate:predicate2];<br />	[request2 setEntity:entitySauv2]; <br /><br />	NSMutableArray *arrayIdProfil2 = [[managedObjectContext executeFetchRequest:request2 error:&amp;error] mutableCopy];<br />	<br />	if (arrayIdProfil2 == nil)<br />	{<br />		// Deal with error...<br />	}<br />	<br />	return arrayIdProfil2;<br />	<br />}



J'ai mit 3 NSlog pour voir ce que me renvoyer certaine variable...


2009-09-08 19:04:57.148 TabCore[58954:207] COUCOUC 0x121b400 &lt;x-coredata://7C6DD418-AF29-43CB-B3D4-23447E50C4B7/Profil/p3&gt;<br />2009-09-08 19:04:57.150 TabCore[58954:207] COUCOUC &lt;Profil: 0x122aa30&gt; (entity: Profil; id: 0x121b400 &lt;x-coredata://7C6DD418-AF29-43CB-B3D4-23447E50C4B7/Profil/p3&gt; ; data: {<br />&nbsp; &nbsp; mesSauvegardes = &quot;&lt;relationship fault: 0x103c520 &#39;mesSauvegardes&#39;&gt;&quot;;<br />&nbsp; &nbsp; nom = Antoine;<br />&nbsp; &nbsp; prenom = mayoussier;<br />&nbsp; &nbsp; taille = 1;<br />})


On voit bien que les requêtes me renvoient l'enregistrement 3

2009-09-08 19:04:57.148 TabCore[58954:207] COUCOUC 0x121b400 &lt;x-coredata://7C6DD418-AF29-43CB-B3D4-23447E50C4B7/Profil/p3&gt;


Cependant j'aurai voulu savoir comment faire pour me retourné simplement le chiffre 3, sans toutes URL...

Sa doit être simplement une connerie a faire mais sa fait plus de 3 heures que je suis dessus.

Est ce que quelqu'un a une idée?

Merci d'avance.

Antoine

Réponses

  • tabliertablier Membre
    00:03 modifié #2
    Tu recherches dans ton NSString le substring "/p" en commençant par la fin.
    Puis tu extrais le substring qui suit le "/p". Sur ce string tu appliques intValue par exemple et tu as ton résultat.
    Toutes les méthodes sont dans la doc de NSString.
  • antoine2405antoine2405 Membre
    00:03 modifié #3
    Merci pour l'astuce, j'était plus partie dans l'idée d'une méthodes toute prête.
  • AliGatorAliGator Membre, Modérateur
    00:03 modifié #4
    Heu ouais, j'y connais quasiment rien en CoreData, mais ta méthode tablier me semble un peu "bourrin"...

    Moi j'irai plutôt dans le sans de récupérer le ManagedObject correspondant à  ta table Profil ; la classe associée, générée depuis le xcdatamodel, s'appelle d'ailleurs très certainement "Profil" elle aussi, et cette classe est un peu " si j'ai bien compris comment marche CoreData " l'image de ta table Profil, donc doit contenir toutes les @property qu'il faut pour accéder aux différents champs de ta table profil.

    Donc sans garantie (car je n'y connais pas grand chose en CoreData j'en ai jamais fait juste vu des projets tout faits, donc bon) mais pour moi quand tu récupères le ManagedObject, si tu sais que ce ManagedObject est en particulier un objet de type Profil (classe qui dérive de ManagedObject), ce qui est forcément le cas car tu as utilisé la NSEntityDescription correspondant à  la table "Profil" dans ta requête... du coup il faut caster ton object récupéré en Profil* : donc au lieu de
    NSManagedObject* object = [managedObjectContext objectWithID:objectID];
    
    moi je mettrais :
    Profil* profilObject = (Profil*)[managedObjectContext objectWithID:objectID];<br />NSLog(@&quot;objet profil récupéré : %@&quot;,profilObject);<br />// et disons que dans ta classe Profil, &quot;image&quot; de ta table &quot;Profil&quot; de CoreData,<br />// tu aies une @property &quot;nom&quot; de type NSString et une @property &quot;id&quot; de type int :<br />NSLog(@&quot;nom: %@ ; ID: %d&quot;,profilObject.nom, profilObject.id);
    




    Après, cela dépend aussi ce que tu entends par "retourner l'ID de ma table Profil" (ce qui n'est d'ailleurs pas super formulé, je suppose que tu voulais dire "récupérer la valeur du champ ID d'un enregistrement de ma table Profil")... Mais ce champ "ID", c'est toi qui l'a créé (comme tu as créé les champs/propriétés "nom" et "prenom", quoi) ? Ou c'est l'ID interne à  CoreData que tu veux, qui n'est pas une propriété que tu as créée mais plutôt la "primaryKey" utilisée en interne par CoreData pour avoir un identifiant unique de ton enregistrement dans ta table ?

    Car si c'est le dernier cas, je ne suis pas sûr que CoreData ne gère les ID genre autoincrement comme on les gère habituellement dans une table SQL : il a ses propres identifiants uniques (objectiD) internes, dont on peu voir la tête d'après tes NSLogs...
    Du coup, d'où tu attends qu'il te retourne "3", tu as vraiment cette valeur dans ta base SQLite, ou c'est juste que c'est le 3e enregistrement que tu as créé et tu vois un "p3" dans le objectID donc tu te dis qu'il doit y avoir un champ "ID" dans ta base SQLite3 contenant la valeur 3... alors que CoreData gère ça certes via SQLite, mais à  sa sauce qd mm...
  • antoine2405antoine2405 Membre
    septembre 2009 modifié #5
    Je m'était mal exprimé.

    Comme tu le dis très bien (comme toujours :) ) je cherche a retourné ID interne...

    Voici comment c'est foutu :

    3903292924_1e9ba8a3f6_b.jpg

    Tu vois bien que le P3 représente ID "3" dans le SQLITE Manager... j'ai testé aussi pour le premier enregistrement et il m'a sorti ID " 1 ".
    Donc je pense que c'est la bonne solution mais par contre je suis choqué qu'il n'y ai pas de méthodes toute prête qui puis permettre de retournée ID.

    C'est tellement vital...

    Donc je pense que je vais utiliser la méthode de tablier même s'il est vrai que sa fait bourrin et merci a toi Aligator pour avoir essayer de m'aider (tu peux continuer si tu veux ^^ ).

    EDIT : Image plus grossseeeee
  • AliGatorAliGator Membre, Modérateur
    00:03 modifié #6
    Ok.
    En effet peut-être un peu étonnant de ne pas pouvoir retourner l'ID, mais... "c'est tellement vital" ?!
    L'ID (utilisé comme primary key pour identifier l'enregistrement de façon unique dans ta table) est normalement un champ "interne", que tu n'as pas à  manipuler directement.
    Si tu fais tes requêtes SQL "à  la main" (SELECT, ...), tu utilises l'ID directement oui (la valeur entière genre 1,2 ou 3 donc).
    Mais si tu utilises les APIs NSManagedObject/NSFetchRequest et donc derrière le mécanisme CoreData, c'est CoreData qui gère tout en interne : normalement tu n'as même pas à  chercher à  comprendre comment est foutue ta table en interne (à  vrai dire, ça pourrait être un storage XML ou PostgreSQL et pas SQLite t'es pas sensé savoir) et donc tu n'as pas à  récupérer l'ID d'un enregistrement, puisque CoreData manipule ces identifiants uniques d'enregistrements via le "objectID" (à  priori un identifiant un peu plus complet contenant un UUID sur 16 caractères etc, comme tu peux le voir dans tes NSLogs)...


    Après, je comprend que quand on est habitués à  manipuler des bases de données comme une base SQLite, ça gène de ne pas pouvoir accéder à  l'ID. Mais les NSFetchRequest sont plutôt orientées pour utiliser CoreData (certes qui utilise SQLite derrière sous le capot, mais bon l'utilisateur n'es pas sensé le voir), donc tu n'es pas non plus sensé savoir qu'il y a un ID sous forme purement "nombre entier" mais utiliser l'objectID pour manipuler les identifiants "d'objets CoreData" (en réalité identifiants d'un enregistrement d'une table de ta base SQLite, mais faut pas le voir comme ça)
  • tabliertablier Membre
    00:03 modifié #7
      :P Oui ma solution est un peu "bourin", mais qu'avez-vous contre le cheval s'il galope ?

    nota: sa fait => ça fait
  • antoine2405antoine2405 Membre
    septembre 2009 modifié #8
    Oaui je comprend ce que tu veux dire par la.

    Mais si on regarde CoreData plus en profondeur, je n'ai pas encore trouvé de moyen (une méthode propre a CoreData) de ne pas avoir de doublons dans ta base de donnée. Parce que proprement dit tu ne pourras jamais avoir de doublons puisqu'il incrément a chaque fois un attribut caché auquel tu n'as aucun accès.

    Pourquoi ? simplement parce que CoreData te crée directement des Primary Key en interne... et on ne te laisse pas le choix.

    Par exemple mon projet regroupe une table profil avec comme attribut "Nom", Prénom, .... J'aurai bien voulu avoir comme Primary Key d'attribut FullName... qui reste un attribut UNIQUE.

    Dans CoreDate j'ai l'impression que ce n'est pas possible...

    Donc après puisque j'ai pas mal fait de PHP et autre chose comme ça, j'ai pas forcement l'intelligence de réfléchir autrement. Il faut un peu de temps... Il y a aussi la philosophie Programmation Orienté Object...

    Après toutes c'est parole, la solution de tablier marche mais il faut que je fignole la chose.

    2009-09-09 10:32:03.146 TabCore[67252:207] COUCOUC 3&gt;
    


    J'arrive a avoir "3>", il est suspect le ">" ^^.

  • AliGatorAliGator Membre, Modérateur
    septembre 2009 modifié #9
    dans 1252486262:

      :P Oui ma solution est un peu "bourin", mais qu'avez-vous contre le cheval s'il galope ?
    J'ai surtout contre le fait que ce n'est pas "safe" dans le sens où ça peut changer ;)

    1) Tu te bases sur la "description" (NSLog(@%@,object) appelle la méthode description" sur object), or cette description n'est là  qu'à  des fins de debug. Apple dit bien que l'on n'est pas sensé se baser dessus pour faire des calculs/conclusions, c'est juste pour afficher dans la console par exemple. Cette description peut tout à  fait changer.

    2) Par contre cette "description" affiche bien la valeur du pointeur de ta variable, puis entre "<...>" des informations... dont la "URIRepresentation", du type "x-coredata://.../p3".
    A la limite s'il faut extraire l'ID de là , c'est donc sur la URIRepresentation du NSManagedObjectID qu'il faut travailler, pas sur le NSManagedObjectID (ou plutôt sa NSString retournée par "description") dont la description n'est pas garantie de garder cette représentation.


    D'ailleurs antoine si tu travailles sur la URIRepresentation et non pas la description retournée par le NSManagedObjectID, tu n'auras plus ce problème de ">" en trop, qui lui vient justement de la "description" (chaà®ne affichée par les NSLog pour le debug) et pollue ton résultat ;)
  • antoine2405antoine2405 Membre
    00:03 modifié #10
    J'y avais songé au URIRepresentation mais en faite les deux méthodes me donnait les mêmes résultats ^^ donc j'ai fait un random dans la tête ... et voila

    Je vais test au cas ou...
  • antoine2405antoine2405 Membre
    00:03 modifié #11
    Moins long ta solution AliGator :
    NSManagedObjectID	*objectID = [arrayIdProfil lastObject];<br />	<br />	NSURL *objectURI = [objectID URIRepresentation];<br />	<br />	NSString *objectURIString =[NSString stringWithFormat:@&quot;%@&quot;, objectURI ];								 <br />	<br />	NSArray *result = [objectURIString componentsSeparatedByString:@&quot;/p&quot;];<br />	<br />	NSString *IDString =[NSString stringWithFormat:@&quot;%@&quot;,[result lastObject] ];<br />	<br />	//NSNumber *IDNumber = [[NSNumber alloc] initWithInt: [result lastObject] ];<br />	<br />	NSLog(@&quot;Nombre : %@&quot;,IDString);
    


    Resultat :

    2009-09-09 11:40:16.135 TabCore[70137:207] Nombre : 3
    


    Merci
  • AliGatorAliGator Membre, Modérateur
    00:03 modifié #12
    Oui...
    Mais en même temps, tu fais la même "erreur" en utilisant [tt]stringWithFormat:@%@[/tt] dans ton code, ce qui marche tout à  fait bien mais n'est pas des plus propre non plus dans ce cas puisque là  encore ça fait appel à  la méthode description" (cette fois de NSURL). Alors qu'il est plus simple mais aussi plus sûr d'utiliser la méthode "absoluteString" de la classe NSURL pour cela ;)
    De même, [tt][result lastObject][/tt] te renvoie déjà  une NSString puisqu'il vient d'un découpage d'une NSString d'après les composants "/p"... donc une simple affectation dans une variable NSString aurait suffit, plutôt qu'un autre stringWithFormat.

    Et enfin, puisqu'on est à  manipuler des NSURLs, plutôt que de découper la chaà®ne (avec componentsSeparatedByString et en se servant de "/p"), il est préférable de manipuler en fait directement les composants de la NSURL. En effet la classe NSURL te permet de manipuler les composants d'une URL, et en particulier de récupérer par exemple le "[tt]lastComponent[/tt]" de cette dernière (ce qui te donnerait "p3" dans ton cas, il faut encore supprimer le "p" qui est au début mais au moins tu es sûr que ce que tu obtiens est ce que tu attends, en tout cas la logique de raisonnement me parait plus cohérente.

    NSManagedObjectID &nbsp; *objectID = [arrayIdProfil lastObject];<br /> &nbsp; <br />NSString* PIDString = [[objectID URIRepresentation] lastCompoenent]; // &quot;p3&quot;<br />int ID = [[PIDString substringFromIndex:1] intValue]; // on zappe le p puis prend l&#39;int<br /><br />NSLog(@&quot;ID : %d&quot;,ID);
    
  • antoine2405antoine2405 Membre
    septembre 2009 modifié #13
    Merci pour l'information par contre j'arrive a obtenir juste "profil/p3" avec cet ligne.

    NSString* PIDString = [[objectID URIRepresentation]relativePath]; // &quot;profil/p3&quot;
    


    Mais pour avoir juste "p3", je vois pas du tout laquelle il faut utiliser.

    surtout que ton histoire de lastComposant.. Je ne vois pas du tout comment tu as fait avec juste les methodes de NSURL..



  • AliGatorAliGator Membre, Modérateur
    00:03 modifié #14
    En fait, de manière générale, une URL est décomposée en plusieurs éléments :
    - Le "scheme" : indique le protocole utilisé, devant les "://". Exemple : "http", "ftp", "https", "file", ...
    - Le nom d'hôte : indique le nom du site, c'est le premier composant après le scheme et avant le premier "/". Exemple : "www.pommedev.com"
    - Le chemin relatif, chemin d'accès qui se trouve après le nom d'hôte. Composé de divers composants (un peu comme des dossiers), séparés par des "/" entre eux.
    -Et il peut y avoir d'autres composants, comme la partie derrière le "?" qu'il y a dans certaines URLs, ou le port à  utiliser, ... mais bon, je ne vais pas rentrer dans le détail.


    Si tu regardes la doc de NSURL, tu peux accéder à  ces divers éléments d'une URL. Ainsi si tu as une URL genre "http://www.pommedev.com/toto/tata/tutu.php"; tu peux en extraire le scheme "http", le hostName "www.pommedev.com", le relativePath "/toto/tata/tutu.php", que tu peux récupérer sous forme d'un tableau de 3 composants {"toto","tata","tutu.php"}... Et le "lastPathComponent"* qui est le dernier élément de ce tableau, donc le dernier élément du relativePath derrière le dernier "/".

    Dans le cas de ton URI "x-coredata://machinchose/profil/p3", bien sûr ce n'est pas une URL vers une page web genre http, mais c'est formé sur le même modèle. Du coup "x-coredata" représente le scheme de l'URL (à  l'image de "http"), machinchose est l'équivalent du hostName, et "/profil/p3" est le relativePath (comme tu le vois puisque c'est ce que tu récupères avec ton code).
    Et le lastPathComponant c'est juste "p3", c'est ça que j'extrais pour ma part.


    Alors après, bon, j'ai tapé de mémoire lastComponent au lieu de lastPathComponent, mais bon un petit tour rapide dans la doc de NSURL t'aurais tout de suite fait comprendre que ma mémoire avait altéré le nom de la méthode, et tu aurais aussi vu les éléments récupérables d'une NSURL et à  quoi servaient les méthodes... donc comment tu pouvais extraire "p3" avec la méthode lastPathComponent...
  • antoine2405antoine2405 Membre
    septembre 2009 modifié #15

    Alors après, bon, j'ai tapé de mémoire lastComponent au lieu de lastPathComponent, mais bon un petit tour rapide dans la doc de NSURL t'aurais tout de suite fait comprendre que ma mémoire avait altéré le nom de la méthode, et tu aurais aussi vu les éléments récupérables d'une NSURL et à  quoi servaient les méthodes... donc comment tu pouvais extraire "p3" avec la méthode lastPathComponent...


    J'était dans la classe CFURL ^^ et la méthode CFURLCopyLastPathComponent.
    Je travail sur l'iphone et cette fonction n'est faite que pour les Mac.. donc c'est pour ça que sa m'a déboussolé.


    Merci de ton aide

    Edit : j'avais regardé dans la doc avant ....
    Edit2:voici le resultat :
    <br />	NSManagedObjectID	*objectID = [arrayIdProfil lastObject];<br />	<br />	<br />	NSString* PIDString = [[objectID URIRepresentation]relativePath]; // &quot;/profil/p3&quot;<br />	<br />	NSString	*lastComponent = [PIDString lastPathComponent];// /p3&quot;<br />	<br />	int ID = [[lastComponent substringFromIndex:1] intValue]; // on zappe le &quot;p&quot; puis prend int<br />	<br />	NSLog(@&quot;ID : %d&quot;,ID);<br />
    

  • AliGatorAliGator Membre, Modérateur
    00:03 modifié #16
    Ah oui tiens la version iPhone de NSURL n'a pas de méthode "lastPathComponent"  ??? au temps pour moi, désolé ;)

    Mais du coup ta dernière version postée me semble ok 
  • antoine2405antoine2405 Membre
    00:03 modifié #17
    Merci Encore. Toujours la quand on a besoin d'aide  <3 <3
  • laudemalaudema Membre
    00:03 modifié #18
    Juste en passant: après avoir lu la doc sur Core Data j'ai le souvenir que l'ID d'un objet est provisoire tant qu'il n'a pas été sauvegardé.
    http://developer.apple.com/mac/library/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/Reference/NSManagedObject.html#//apple_ref/doc/uid/TP30001171-BAJGEDIA
    [move]
    Important:  If the receiver has not yet been saved, the object ID is a temporary value that will change when the object is saved.
    [/move]
Connectez-vous ou Inscrivez-vous pour répondre.