2010-02-12 10 views
51

Quiero ver si un objeto persiste en Core Data o no. Por ejemplo, tengo Amigos en Core Data, y los identifico por firstName. Puedo consultar datos básicos para ver si se conoce a "George". Si la matriz del conjunto de resultados contiene más de cero objetos, sé que George está allí. Pero Core Data carga todo en la memoria, y en realidad solo quiero saber si George está almacenado o no.¿La forma más rápida de verificar si un objeto existe en Core Data o no?

¿Cómo lo haría de la manera más eficiente?

+0

como se menciona en @Jon, la documentación oficial de Apple Core Data tiene un [capítulo] (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#// apple_ref/doc/uid/TP40003174-SW4) llamado 'Implementación de Find-or-Create Efficiently' que se pasa por alto fácilmente y detalla varias estrategias para reducir la huella de memoria. – ssc

Respuesta

92

instalación de una solicitud de datos básicos y, en lugar de realmente emisión de la consulta, haga lo siguiente:

NSError *error = nil; 
NSUInteger count = [managedObjectContext countForFetchRequest:request 
                 error:&error]; 
if (!error) { 
    return count; 
} else { 
    return 0; 
} 

En la práctica, el método countForFetchRequest:error: devuelve el número de objetos de una determinada solicitud se ha podido recuperar habría vuelto si tuviera pasado a executeFetchRequest:error:.


Editar:(por Regexident)

Como Josh Caswell correctamente comentado, la forma correcta para controlar los errores es o bien esto:

if (count == NSNotFound) { 
    NSLog(@"Error: %@", error); 
    return 0; 
} 
return count; 

o este (sin registro de errores):

return (count != NSNotFound) ? count : 0; 
+0

y debería ser más eficiente porque bajo el capó, el motor SQL debería estar haciendo y COUNT en lugar de un SELECT –

+14

Tenga en cuenta que el manejo de errores aquí es incorrecto; [como suele ser el caso en Cocoa] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html%23//apple_ref/doc/uid/TP40001806- CH204-SW1), debe verificar el valor de retorno directo ('count') antes de verificar el objeto de error. En este caso, [los documentos dicen] (http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html) que un retorno de 'NSNotFound' señala una error. –

+0

Massimo, ¿cómo responde esta publicación a la pregunta del OP? El OP preguntó cómo podía determinar si un objeto con un valor específico, es decir, "George", existe en la tienda persistente. – Pavan

6

De acuerdo con Core Data Documentation, no debe seguir buscando para ver si existen objetos.

There are many situations where you may need to find existing objects (objects already saved in a store) for a set of discrete input values. A simple solution is to create a loop, then for each value in turn execute a fetch to determine whether there is a matching persisted object and so on. This pattern does not scale well. If you profile your application with this pattern, you typically find the fetch to be one of the more expensive operations in the loop (compared to just iterating over a collection of items). Even worse, this pattern turns an O(n) problem into an O(n^2) problem.

Edición 16 de de marzo de:
No soy un experto en db, pero ya que la gente está pidiendo una solución más eficiente, tenga en cuenta este conjunto:

set1 = [apple, orange, banana, pineapple, lettuce] 

Queremos averiguar si [mango, apple, grape] es una parte de este conjunto.

Los documentos nos dicen que no debemos iterar a través de [mango, manzana, uva] y consultar la base de datos buscando cada elemento por turno porque es lento.

considerar esta solución:

Hash los conjuntos a nivel de servidor:

hash([mango, apple, grape]) = 234095dda321affe... 

Puede entonces derivación del núcleo de datos por completo al pedir el servidor si algo cambiado. Si los conjuntos son diferentes, puede volcar los objetos en un contexto de objeto administrado y realizar un guardado masivo.

Si realmente desea ver si cada objeto a su vez forma parte del conjunto, puede hacer una búsqueda basada en una característica indexada, como "fruta con piel".

+1

Así que no entiendo. ¿Cuál es la solución propuesta? ¿Simplemente dicen que es incorrecto comprobar si ya existen los mismos datos? Creo que eso es falso ... Sé que es muy tarde, pero creo que esto sigue siendo un problema. – Tariq

+0

@Jon ¿Cuál es la forma correcta, entonces? – Developer

24

Sí, definitivamente hay un método mejor.Configurar una petición de recuperación como de costumbre, pero, en lugar de llegar a ejecutarlas, sólo tiene que pedir el número de objetos que habría vuelto si se hubiera pasado a executeFetchRequest: Error:

Esto se puede hacer usando

- (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error:(NSError **)error; 

Algo como esto:

- (int) numberOfContacts{ 

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    NSManagedObjectContext *managedObjectContext = yourManagedObjectContext; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:managedObjectContext]; 
    [request setEntity:entity]; 

    NSError *error = nil; 
    NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error]; 
    [request release]; 

    if (!error){ 
     return count; 
    } 
    else 
     return -1; 

} 
+2

Esto es idéntico a la respuesta aceptada. – jrturton

+11

Sí, pero he incluido el método completo y los detalles. – shaikh

+4

bueno para noobs como yo Faizan :) – Allen

7

Si el objetivo es comprobar si el objeto existe la solución es poner en práctica este método en su amigo Modelo:

-(BOOL)exist 
{ 
    NSManagedObjectContext *managedObjectContext = yourManagedObjectContext; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Friends" inManagedObjectContext:managedObjectContext]; 

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    [request setEntity:entity]; 
    [request setFetchLimit:1]; 
    [request setPredicate:[NSPredicate predicateWithFormat:@"firstName == %@", self.firstName]];  

    NSError *error = nil; 
    NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error]; 

    if (count) 
    { 
     return YES; 
    } 
    else 
    { 
     return NO; 
    } 
} 
+0

Debo agregar esto a MyModel.swift que se crea en combo con MyModel + CoreDataProperties.swift, ¿correcto? ¿Y tienes una versión 2.0 rápida? Ah, y ¿cómo puedo llamar a esta función? Si (....... existe() == "sí") ??? – alex

+0

Ah, ¿y cómo verificaría un firstName, por ejemplo, Graham? – alex

+1

en mi ejemplo, el método está en el modelo para obtener la propiedad firstname. Y no se olvide de obtener su ManageObject. No tengo ningún ejemplo rápido. –

Cuestiones relacionadas