2009-08-28 18 views
22

Tengo un modelo de datos básicos en el que una entidad de tarea incluye una relación opcional de muchos días excluidos de la entidad ExcludedDay. Una de las propiedades de ExcludedDay es day, que es un objeto NSDate. La entidad ExcludedDay tiene una relación inversa obligatoria one-to con la entidad Task.¿Cómo configurar correctamente una NSPredicate para una relación de muchos cuando se utilizan datos principales?

Para buscar las tareas para un día específico, necesito asegurarme de que el día especificado no aparezca como la propiedad day de cualquier entidad ExludedDay.

empecé a tratar

NSPredicate *dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"ALL excludedDays.day != %@", today]; 

Sin embargo, a pesar de lo que dice la documentación, TODO no funciona y la aplicación inicia una excepción: Terminación de aplicación debido a excepción no detectada ‘NSInvalidArgumentException’, razón: ‘predicado no compatible.

Después de publicar la misma pregunta en este foro, yo era capaz de idear el siguiente predicado con la ayuda de varias personas:

NSPredicate * dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"[email protected] == 0 || ([email protected] > 0 && NONE excludedDays.day == %@))", today]; 

Si bien esto funcionó al principio, Acabo de descubrir que esto sólo funciona cuando la entidad ExcludedDay contiene SOLAMENTE un día. Tan pronto como la entidad ExcludedDay contiene más de un día para la misma tarea, este predicado deja de funcionar. Como resultado, se selecciona una tarea para un día, aunque el día aparezca como un día en la entidad ExcludedDay, lo cual es, por supuesto, incorrecto. El problema no está relacionado con el día de la propiedad como un objeto NSDate: reemplazando el día con el NSString correspondiente o de forma equivalente con un entero, todavía tengo el mismo problema y un comportamiento incorrecto.

¿Cuál es la forma correcta de implementar el predicado en este caso? ¿Puede tratarse de un error relacionado con el operador agregado ANY cuando se usan datos centrales? Gracias de antemano, esto ahora me está volviendo loco.

Respuesta

42

Resulta que este es otro problema con la falta de documentación y/o inconsistente.

El predicado correcto en este caso es la siguiente:

[NSPredicate predicateWithFormat:@"([email protected] == 0) OR (0 == SUBQUERY(excludedOccurrences, $sub, $sub.day == %@)[email protected])", today] 

En el predicado, una sub consulta se utiliza para probar si el número de excludedOccurrences relacionados con una fecha que coinciden con la fecha de la prueba es igual a cero.Sin embargo, la documentación es engañosa. Esto es lo que dice la Guía de programación de predicados con respecto al uso de predicados en conjunto con muchas relaciones.

Uso de predicados con las relaciones

Si utiliza una relación de muchos, la construcción de un predicado es ligeramente diferente. Si se desea obtener Departamentos en los que al menos uno de los empleados tiene el nombre "Mateo", por ejemplo, se utiliza un cualquier operador, como se muestra en el siguiente ejemplo:

NSPredicate *predicate = [NSPredicate predicateWithFormat: 
    @"ANY employees.firstName like 'Matthew'"]; 

Si usted quiere encontrar Departamentos en la que todos los empleados se les paga más de una cierta cantidad, se utiliza un tODO operador como se muestra en el siguiente ejemplo:

float salary = ... ; 
NSPredicate *predicate = [NSPredicate predicateWithFormat: 
    @"ALL employees.salary > %f", salary]; 
+0

¿Quizás sepa cómo escribir la expresión con SUBQUERY con las clases NSExpresion y NSComparisonPredicate? Con su respuesta, decidí que la mi pregunta: http://stackoverflow.com/questions/2006927/whats-better-way-to-build-nspredicate-with-to-many-deep-relationships Gracias – Victor

+1

Muchas gracias por esta respuesta, realmente útil. – Maria

1

Muy curioso sobre cómo solucionar esto, configuré un pequeño proyecto y creé el contexto que está utilizando.

NSDate *today = [NSDate date]; 
NSMutableArray *objects = [NSMutableArray array]; 

{ 
    NSArray *day = [NSArray arrayWithObjects:today, [today dateByAddingTimeInterval:20.0f], nil]; 
    NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:@"day"]; 
    NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:@"excludedDay"]; 

    [objects addObject:object]; 
} 

{ 
    NSArray *day = [NSArray arrayWithObjects:[today dateByAddingTimeInterval:20.0f], nil]; 
    NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:@"day"]; 
    NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:@"excludedDay"]; 

    [objects addObject:object]; 
} 


NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NONE excludedDay.day == %@", today]; 
NSArray *filtered = [objects filteredArrayUsingPredicate:predicate]; 

NSLog(@"%@", filtered); 

Esto le da al objeto cuando:

  1. La matriz día está vacía
  2. La matriz día no contiene la fecha 'hoy'

Esto no le da el objeto cuando:

  1. La matriz del día contiene el hoy
    • No importa cuántos objetos de la matriz día son
+1

por desgracia, esto es un entorno completamente diferente: mi contexto se basa en la base de datos y el iPhone SDK 3.0 o 3.1. Parece que el marco de datos principales no maneja correctamente los predicados cuando se sigue una relación de muchos. Ya he archivado un error y los ingenieros de Apple están trabajando en ello, pero todavía no hay respuesta de ellos. –

+1

Entonces es de hecho un problema transmitido por Core Data, ya que usando el mismo predicado pero sin Core Data está funcionando correctamente (como se vio en mi intento de imitar el mismo contexto (relacionado con Foumdation)) – Joost

+1

me ayudó en 2011 :) +1 –

Cuestiones relacionadas