核心数据:在两个实体中查找的 NSPredicate
Posted
技术标签:
【中文标题】核心数据:在两个实体中查找的 NSPredicate【英文标题】:Core Data: NSPredicate that looks in two Entities 【发布时间】:2013-01-04 09:37:56 【问题描述】:问题是我不知道如何制作一个在两个实体中查找的NSPredicate
。有什么想法吗?
假设我有 2 个实体:
Library:
1 lib_id
2 name
3 address
和:
Books
1 book_id
2 book_name
3 book_author
4 lib_id
它们之间没有任何核心数据关系。我想发出一个获取请求,该请求将返回一个 NSArray,其中包含至少一本书的所有库。
我认为它是这样的:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescriptor *entity = [NSEntityDescriptor entityForName:@"Books" inManagedObjectContext:context];
// some NSPredicate...
array = [context executeFetch ...];
【问题讨论】:
不要将 Xcode 标签用于与 Xcode 无关的问题! 在两个实体之间建立关系。使用books.@count > 0
之类的谓词创建针对Library
的请求。这样,您可以节省时间;)
由于某些原因我无法建立关系...
如果您不能按照我的建议进行操作,您需要创建两个不同的请求:一个用于Books
,一个用于Library
。您需要在内存中加载这两种类型的对象,然后针对lib_id
执行一些检查。也许其他人可以提出其他方法。
【参考方案1】:
这比你想象的要复杂,但也不是不可能。
您的数据模型在两个实体上都使用lib_id
,以及您无法在实体之间添加Core Data 关系的评论表明您陷入了一个经典陷阱:您正在处理Core像关系数据库这样的数据。 Core Data 的 API 不像关系数据库那样设计。你可以让它工作,但你应该意识到你会不遗余力地让 Core Data 变得比必要的更困难。如果下面的解决方案看起来很复杂,那是因为你做错了 Core Data。
如果您使用 Core Data 的预期用途——在这种情况下是两个实体之间的关系——查找会很简单。您可以对每个 Library
进行一次提取,而其 books
关系中没有任何条目。
话虽如此,您分两步解决眼前的问题。
首先,获取用于Books
实例的lib_id
的每个唯一值。以下将为您提供一个NSArray
,其中包含与唯一值匹配的字符串:
NSFetchRequest *bookRequest = [NSFetchRequest fetchRequestWithEntityName:@"Books"];
[bookRequest setPropertiesToFetch:@[@"lib_id"]];
[bookRequest setResultType:NSDictionaryResultType];
[bookRequest setReturnsDistinctResults:YES];
NSError *error = nil;
NSArray *libIdsInBooksDicts = [[self managedObjectContext] executeFetchRequest:bookRequest error:&error];
if (libIdsInBooksDicts == nil)
NSLog(@"Fetch error: %@", error);
return;
NSArray *libIdsInBooks = [libIdsInBooksDicts valueForKey:@"lib_id"];
上面的最后一行是因为libIdsInBooksDicts
实际上包含一个字典数组,而每个字典又都有一个名为lib_id
的键和一个作为实际ID 的值。您只需要这些值。
接下来,查找lib_id
在您刚刚获得的列表中的每个Library
:
NSFetchRequest *libRequest = [NSFetchRequest fetchRequestWithEntityName:@"Library"];
[libRequest setPredicate:[NSPredicate predicateWithFormat:@"lib_id in %@", libIdsInBooks]];
error = nil;
NSArray *librariesWithAtLeastOneBook = [[self managedObjectContext] executeFetchRequest:libRequest error:&error];
if (librariesWithAtLeastOneBook == nil)
NSLog(@"Fetch error: %@", error);
return;
【讨论】:
+1 汤姆。好答案。我已经在评论中指出了;)【参考方案2】:NSFetchedResultsController
可以帮助使用 sectionNameKeyPath 获取结果。
- (id)initWithFetchRequest:(NSFetchRequest *)fetchRequest
managedObjectContext:(NSManagedObjectContext *)context
sectionNameKeyPath:(NSString *)sectionNameKeyPath
cacheName:(NSString *)name;
如果将 lib_id 作为 sectionNameKeyPath 传递,您将获得多个部分中的数据,每个部分关联不同的 lib_id。
【讨论】:
【参考方案3】:一次提取 == 一个 DISTINCT 实体。
但您可以拥有 N 个相关实体 => 让一个实体相互继承
所以 .. 你可以让 A1 扩展 A 和 A2 扩展 A: => A1 & A2 存储在一个表中,可以一次获取它们(获取所有 As)
但是..您无法获取不相关的 A 和 B: => 一次获取无法做到这一点
【讨论】:
以上是关于核心数据:在两个实体中查找的 NSPredicate的主要内容,如果未能解决你的问题,请参考以下文章