在coreData xcode iphone中创建一个复合谓词

9

你好,我正在处理包含3个实体(班级、学生、考试记录)和它们之间关系的核心数据,具体如下:

Class<------>> Students <------> ExamRecord

我为获取5年级学生名单创建了一个谓词。
NSString * fmt2 = @"studentsToClass.className=%@";
NSPredicate * p2 = [NSPredicate predicateWithFormat:fmt2,@"5th",nil];

通过这个代码,我可以获取所有五年级的学生。

现在,我还想对已经获取的学生应用另一个筛选条件。

获取考试记录“result”为“Pass”的学生。在ExamResult实体中,"result"是学生的属性。

如何使用复合谓词来实现这一点?

如果我有错,请纠正我。

将不胜感激。

谢谢。

4个回答

30

您可以使用复合谓词:

NSPredicate *p1 = [NSPredicate predicateWithFormat:@"studentsToClass.className = %@", @"5th"];
NSPredicate *p2 = [NSPredicate predicateWithFormat:@"studentsToExamRecord.result = %@", @"Pass"];
NSPredicate *p = [NSCompoundPredicate andPredicateWithSubpredicates: @[p1, p2]];

或者你可以将测试用例与“AND”组合:

NSPredicate *p = [NSPredicate predicateWithFormat:@"studentsToClass.className = %@ AND studentsToExamRecord.result = %@",
      @"5th", @"Pass"];

请注意,predicateWithFormat 的参数列表不是以 nil 结尾的。参数的数量由格式字符串中格式说明符的数量确定。

@Fogmeister:我很想知道。 - Martin R
@MartinR 感谢您的帮助,但我仍然无法获取学生的结果。我的谓词变成了:studentsToClass.className == "5th" AND studentsToExamRecord.result == "Pass" 请帮忙并指出我的错误。 - sagar
@sagar:你是否遇到了错误或没有结果?也许可以展示一下实体是如何定义以及对象是如何创建的。如果省略谓词,你是否能够获取所有对象? - Martin R
如果我应用 studentsToClass.className == "5th",那么我会得到所有学生,否则没有记录被找到。 - sagar
@sagar:但是这个谓词看起来没问题。你确定从Students到ExamRecord的关系已经建立了吗?"result"属性的值真的是"Pass",而不是小写吗? - Martin R

2
首先,你不应该真正称呼 学生 - 班级 关系为 studentsToClass。关系的名称应反映另一端是什么类型的对象。
例如:
在这种情况下,StudentClass 的关系应该称为 class,因为那里的对象是单个 Class 实体。反向关系不应称为 classToStudent,而应称为 students,因为那里的对象是多个 StudentsNSSet
编辑:
只是补充一下。关系的名称应解释它存在的原因。我们可以看到关系是从班级到学生的,但如果你称之为“classToStudent”,它就没有任何解释。此外,如果您有第二个从班级到学生的关系,您会怎么称呼它?如果您称其为 attendeespupilsattendingStudents 等,它会赋予关系含义。
解决方案:
在这个例子中,我将按照我的方式称呼它们,你会发现这使得理解起来更容易了一些...
无论如何...
NSPredicate *classPredicate = [NSPredicate predicateWithFormat:@"class.className = %@", @"5th"];
NSPredicate *passPredicate = [NSPredicate predicateWithFormat:@"result.name = %@", @"Pass"];

NSCompoundPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[classPredicate, passPredicate]];

谢谢你的帮助,但我仍然无法获取学生。我的谓词变成了:studentsToClass.className == "5th" AND studentsToExamRecord.result == "Pass" 请帮忙并指出我的错误。 - sagar

0

谓词也可以使用复合谓词进行嵌套(适用于Swift)。

        let orPredicate = NSCompoundPredicate(type: .or, subpredicates: [date_1KeyPredicate, date_2KeyPredicate])

        let functionKeyPredicate = NSPredicate(format: "function_name = %@", self.title!)

        let andPredicate = NSCompoundPredicate(type: .and, subpredicates: [orPredicate, functionKeyPredicate])

0

首先,你引用的谓词已经是错误的了。你应该引用托管对象,而不是它的属性(即不是Classname)。正确的写法应该是:

[NSPredicate predicateWithFormat:@"class = %@", classObject]; 

此外,您应该为变量和属性选择更易读的名称。因此,不要使用fmt2,而是使用formattingString。不要使用studentsToClass,而是使用form(“class”是Objective-C中的特殊单词)。您明白了吧。
所以,您可以像这样完成所需的复合谓词(简短版本):
[NSPredicate predicateWithFormat:@"class = %@ && record.result = %@",
         classObject, @"Pass"]; 

如果你真的需要更高层次的抽象(我怀疑),那么复杂版本如下:

classPredicate = [NSPredicate predicateWithFormat:@"class = %@", classObject]; 
resultPredicate = [NSPredicate predicateWithFormat:@"record.result = %@", @"Pass"];
finalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:
    @[classPredicate, resultPredicate]];

如果两个子谓词都是可选的,即A或B而不是A和B,那么如何将它们合并为一个? - Krati Jain
那将是一个单独的SOF问题;-)。 - Mundi
是的,我找到了 :) 它是使用 orPredicateWithSubpredicates 完成的。 - Krati Jain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接