查询/过滤核心数据实体与共同父项不符合键值

时间:2014-06-11 14:27:23

标签: core-data nspredicate

有没有办法创建谓词查询来过滤子实体?我希望能够返回一个结果集,并将过滤应用于子项。

例如我有Shape。圆形正方形是形状,我想这样做:

NSManagedObjectContext * context = [self managedObjectContext];

Circle * c = [NSEntityDescription insertNewObjectForEntityForName:@"Circle" inManagedObjectContext:context];
c.radius = @(10);

Square * s = [NSEntityDescription insertNewObjectForEntityForName:@"Square" inManagedObjectContext:context];
s.width = @(100);
s.height = @(200);


NSFetchRequest * f= [NSFetchRequest fetchRequestWithEntityName:@"Shape"];
f.predicate =[NSPredicate predicateWithFormat:@" radius = 10 OR hight = 200"];;
NSArray * results = [context executeFetchRequest:f error:nil];
NSLog(@"%@",results);

这会产生一个在执行获取请求时调用的键值异常,因为正方形没有半径,并且圆没有高度和宽度。

2 个答案:

答案 0 :(得分:2)

您只能通过两种方式实现这一目标 - 向所有实体添加所有可能的属性(将radius添加到Squarewidthheight添加到{{1} })或执行两个获取请求,一个用于圆圈,一个用于方块。我是第二种方法。

Circle

答案 1 :(得分:2)

我会对Shape实体进行非规范化:

Shape实体中包含所有属性(在任何情况下[对于SQLite商店]都是CoreData的内部实现)并且仅为特殊形状(Circle创建实现(@dynamic), Square,......) 您可以将此非规范化限制为仅需要搜索的属性。

备注:

  1. 您可能希望避免为Shape实体中的非规范化属性设置默认值,因为继承实体在使用时仍会返回值:[object valueForKey:@"somepropertynamefromspecializedclass"];。通过这种方式,他们会为此类密钥返回nil
  2. 您可能还想向shapeType实体添加Shape媒体资源,这样您就可以限制搜索特定类型的Shape
  3. 这样,您只需要一次获取即可获得所需的对象,并使用一个FRC跟踪它们。

    示例:

    Shape:[abstract entity](shapeType,name,radius,width,height):为此实体生成实现(Shape.h和Shape.m),但删除非规范化属性的实现(半径) ,宽度,高度) 所以你的Shape .h文件如下:

    @interface Shape : NSManagedObject
    @property (nonatomic, retain) NSString * name;
    @property (nonatomic, retain) NSString * shapeType;
    //radius ,width and height were removed (REMEMBER TO REMOVE THEM FROM YOUR .M FILE AS WELL)
    @end
    

    Shape .m文件:

    @implementation Shape
    @dynamic name;
    @dynamic shapeType;
    @end
    

    Circle:[继承自Shape]()

    Circle .h档案:

    @interface Circle : Shape
    @property (nonatomic,strong) NSNumber* radius;
    @end
    

    Circle .m文件:

    @implementation Circle
    @dynamic radius;
    @end
    

    Rectangle:[继承自Shape]() 实现与Circle

    非常相似

    现在您可以在代码中的某处执行:

    Circle* c = (Circle*)[NSEntityDescription insertNewObjectForEntityForName:@"Circle" inManagedObjectContext:self.managedObjectContext];
    c.name = @"circle";
    c.shapeType = @"c";
    c.radius = @(100);
    
    Rectangle* rect = (Rectangle*)[NSEntityDescription insertNewObjectForEntityForName:@"Rectangle" inManagedObjectContext:self.managedObjectContext];
    rect.name = @"rectangle";
    rect.shapeType = @"r";
    rect.width = @(150);
    rect.height = @(200);
    
    [self.managedObjectContext save:nil];
    [self.managedObjectContext reset];
    
    NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"Shape"];
    r.predicate = [NSPredicate predicateWithFormat:@"width > %@ OR radius > %@",@(100),@(90)];
    NSArray* res = [self.managedObjectContext executeFetchRequest:r error:nil];