使用聚合操作的崩溃:“ALL”在Core Data iOS应用程序中 [英] Crash using Aggregate Operation: "ALL" in a Core Data iOS Application

查看:112
本文介绍了使用聚合操作的崩溃:“ALL”在Core Data iOS应用程序中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个iphone应用程序,我有一个简单的多对多关系设置与组和联系人对象。一个群组可以有多个联系人,而联系人可以属于多个群组。



我试图使用以下谓词选择特定联系人不属于的所有群组。 (注意:uid字段是我用来唯一标识联系人实体的字符串字段)

  [NSPredicate predicateWithFormat:@ALL contact.uid!=%@,contactUId] 

根据Apple的谓词编程指南,操作有效,但我收到以下异常,表明这是不支持的谓词:

  ***由于未捕获异常终止应用程序'NSInvalidArgumentException',reason:'不支持的谓词(null)'



我可以使用类似的谓词联系人已经属于使用此谓词的所有组,因此看起来我已正确定义了所有关系和字段。

  [NSPredicate predicateWithFormat:@ANY contacts.uid ==%@,contactUId] 

在构造谓词时抛出,而不是当我试图实际执行获取请求时,因此它似乎与我使用的语法相关,而不是与Core Data支持相关。

核心数据编程指南

blockquote>

在提取和存储类型之间有一些交互。在XML,二进制和内存存储中,对谓词和排序描述符的评估在Objective-C中执行,可访问所有Cocoa的功能,包括NSString的比较方法。另一方面,SQL存储库将谓词和排序描述符编译为SQL,并在数据库本身中计算结果。


接下来描述对使用NSPredicate与NSSQLiteStoreType的一些其他限制,但是在这里使用ALL是一个(未记录的)限制,与获取请求如何发出SQL有关。



CoreData为您的模式生成三个表格:




  • 联系人表格




  • 所以当你调用myGroup.contacts,这样的东西运行:

      select *从Group join JOIN_TABLE Group.pk == JOIN_TABLE.group_pk join JOIN_TABLE.contact_pk上的联系人== Contact.pk其中Group.pk == 12 



    无论如何,要真正完成你的查询,你需要这样的东西。我在一个实际的SQLite CD数据库测试这个,所以表名看起来很奇怪,但它仍然应该是可理解的:

     选择ZGROUP .Z_PK作为outer_pk从ZGROUP其中myUID不在
    (选择ZCONTACT.ZUID作为contact_uid从ZGROUP连接Z_1GROUPS在Z_1GROUPS.Z_2GROUPS == ZGROUP.Z_PK加入ZCONTACT在Z_1GROUPS.Z_1CONTACTS == ZCONTACT.Z_PK其中ZGROUP。 Z_PK == outer_pk)



    我不是SQL专家,但我的观察首先是查询将会很慢,其次,它是从我们开始的NSPredicate的一个很长的路。因此,只有通过大量的努力,CD才能与您想要做的SQL查询结合起来,而且它将会出现的查询不会比ObjC中的一个朴素的实现更好。



    无论什么值得,苹果开发商说这里,所有在SQLite不支持,文档相反是错误的。



    无论如何,你实际上应该做的是这样的:

      NSFetchRequest * fetchRequest = ... 
    NSArray * result = [moc executeFetchRequest:fetchRequest error:& err];
    result = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@ALL contacts.uid!=%@,contactUId]];

    这将在软件中评估谓词。


    I'm working on an iphone application and I have a simple many-to-many relationship set up with Group and Contact objects. A group can have many contacts and contacts can belong to multiple groups.

    I'm trying to select all groups that a particular contact does NOT already belong to using the following predicate. (Note: the uid field is a string field that I used to uniquely identify contact entities)

    [NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]
    

    According to Apple's Predicate Programming Guide, the ALL aggregate operation is valid but I get the following exception indicating that this is an unsupported predicate:

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate (null)'
    

    I can use a similar predicate to select all groups that a contact does already belong to using this predicate so it appears that I have all of the relationships and fields defined properly.

    [NSPredicate predicateWithFormat:@"ANY contacts.uid == %@", contactUId]
    

    The exception is thrown when constructing the predicate and not when I'm trying to actually execute the fetch request so it seems to be related to the syntax I'm using rather than Core Data support. What am I doing wrong?

    解决方案

    The Core Data Programming Guide says

    There are some interactions between fetching and the type of store. In the XML, binary, and in-memory stores, evaluation of the predicate and sort descriptors is performed in Objective-C with access to all Cocoa's functionality, including the comparison methods on NSString. The SQL store, on the other hand, compiles the predicate and sort descriptors to SQL and evaluates the result in the database itself.

    It goes on to describe some other limitations on the use of NSPredicate with NSSQLiteStoreType, but your use of "ALL" here is an (undocumented) limitation that has to do with how the fetch request emits SQL.

    Under the hood, CoreData generates three tables for your schema:

    • a table for Contact
    • a table for Group
    • a join table that relates them

    And so when you call myGroup.contacts, something like this gets run:

    select * from Group join JOIN_TABLE on Group.pk == JOIN_TABLE.group_pk join Contact on JOIN_TABLE.contact_pk == Contact.pk where Group.pk == 12
    

    There's a lot going on behind one dot character!

    Anyway, to actually fulfill your query, you'd need something like this. I tested this on an actual SQLite CD database, so the table names look strange, but it should still be comprehensible:

    select ZGROUP.Z_PK as outer_pk from ZGROUP where "myUID" not in 
    (select ZCONTACT.ZUID as contact_uid from ZGROUP join Z_1GROUPS on Z_1GROUPS.Z_2GROUPS == ZGROUP.Z_PK join ZCONTACT on Z_1GROUPS.Z_1CONTACTS == ZCONTACT.Z_PK where ZGROUP.Z_PK == outer_pk)
    

    I'm no SQL expert, but my observations are first of all that this query is going to be slow, and second of all that it is kind of a long ways from the NSPredicate that we started with. So it would be only through a great deal of effort that CD could up with an SQL query for what you want to do, and the query that it would come up with would not be much better than a naive implementation in ObjC.

    For whatever it's worth, an Apple developer says here that ALL is unsupported in SQLite and the documentation to the contrary is wrong. That documentation is still there in 2013 though, so nobody seems to have done anything about it.

    Anyway, what you should actually do is something like this:

    NSFetchRequest *fetchRequest = ...
    NSArray *result = [moc executeFetchRequest:fetchRequest error:&err];
    result = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]];
    

    This will evaluate the predicate in software.

    这篇关于使用聚合操作的崩溃:“ALL”在Core Data iOS应用程序中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆