如何仅获取Core Data中的第一条记录?

时间:2009-07-29 01:07:45

标签: iphone core-data

我正在使用Core Data,我只想获取数据集中的第一条记录,是否可能?

5 个答案:

答案 0 :(得分:75)

您可以在NSFetchRequest上使用setFetchLimit:方法来限制提取的记录数。所以如果你只想要第一条记录:

// Given some existing NSFetchRequest *request and NSManagedObjectContext *context:
[request setFetchLimit:1];
NSError *error;
NSArray *results = [context executeFetchRequest:request error:&error];

请注意,对executeFetchRequest:error:的调用仍将返回NSArray;你仍然需要先从数组中拉出第一个对象才能使用它,即使它是一个大小为1的数组。

另一种效率较低的方法:根据您的商店类型,限制提取可能会产生显着的性能提升。但是,如果它没有,或者您不担心性能,并且稍后可能会使用更多数据,那么您可以提前将第一个对象拉出阵列:

// Given some existing result NSArray *results:
NSManagedObject *firstManagedObject = [results firstObject];

如果您确定该数组中有一个对象,您甚至可以通过这样做将其放入另一个数组(例如在UITableViewController中使用):

// Again, with some NSArray *results:
NSArray *singleObjectResult = [results subarrayWithRange:NSMakeRange(0, 1)];

答案 1 :(得分:13)

当然,这部分取决于“第一条记录”的含义。您可能不仅需要将获取限制设置为1,还需要在获取中对结果进行排序。

例如,我的数据库中有一堆User个对象,我想找到第一个创建帐户的人。 (假设我已经拥有User的模型,包括一个名为accountCreatedDate的属性。)

NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"accountCreatedDate" ascending:YES]; // ascending YES = start with earliest date

NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = entity;
request.sortDescriptors = @[ sortDescriptor ];
request.fetchLimit = 1;

NSError *error;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];

User *result = fetchResults.firstObject; // nil on failure; check value of 'error'

如果您在限制提取之前没有对结果进行排序,则无法确定将“首先”返回哪些结果。

答案 2 :(得分:2)

我使用Objective-C类别添加名为NSManagedObject的{​​{1}}类方法。

源代码

firstInManagedObjectContext:

用法

将这些文件添加到您的项目中,并确保将它们链接到您的目标。然后,使用// NSManagedObject+Additions.h @interface NSManagedObject (Acani) + (NSString *)entityName; + (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context; + (NSManagedObject *)firstInManagedObjectContext:(NSManagedObjectContext *)context; @end // NSManagedObject+Additions.m #import "NSManagedObject+Additions.h" @implementation NSManagedObject (Acani) + (NSString *)entityName { return NSStringFromClass([self class]); } + (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context { return [NSEntityDescription entityForName:self.entityName inManagedObjectContext:context]; } + (NSManagedObject *)firstInManagedObjectContext:(NSManagedObjectContext *)context { NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; [fetchRequest setEntity:[self entityInManagedObjectContext:context]]; [fetchRequest setFetchLimit:1]; NSError *error; NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; [fetchRequest release]; if (fetchedObjects == nil) { NSLog(@"Fetch sender error %@, %@", error, [error userInfo]); return nil; } else if ([fetchedObjects count] > 0) { return [fetchedObjects objectAtIndex:0]; } return nil; } @end 类方法的#import "NSManagedObject+Additions.h"文件中的.m

firstInManagedObjectContext:的任何具体(非抽象)子类调用它。只需传递NSManagedObjectContext从中获取托管对象即可。该方法从调用它的类的名称中检测NSManagedObjectContext *context。只需记住将结果转换为干净的构建(没有警告)。

我正在将它用于托管对象类,我知道我只有一个已保存的实例。如果您有多个已保存的实例,则可能需要添加(NSString *)entityName作为@Craig McMahon建议。如果在同一设备上创建了所有对象,您还可以尝试按NSSortDescriptor而不是objectID进行排序。但是,我不确定是否订购了对象ID。

实施例

想象一下,你有一个来自accountCreatedDate的{​​{1}}对象。你可以这样做:

Event

在阅读Pragmatic Studio's iOS 4 Blocks Tutorial之后,我意识到可以通过添加另一个函数来改进此代码并使其更加模块化,将其称为NSManagedObjectContext并添加Event *event = (Event *)[Event firstInManagedObjectContext:context]; (这将使+ fetch作为其论点)& NSFetchRequestBlock分别作为自定义获取请求和获取请求错误的处理的参数。我挑战你解决这个问题! :)

答案 3 :(得分:2)

只需将fetchLimit的{​​{1}}属性设置为1,然后使用NSFetchRequest方法从结果NSArray中选取第一个元素,以避免firstObject index out of bound for empty array错误。

以下是代码示例:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ENTITY_NAME" inManagedObjectContext:yourMoc];
NSPedicate *predicate = [NSPredicate predicateWithFormat:@"PREDICATE FORMAT"];
[request setEntity:entity];
[request setPredicate:predicate];
[request setFetchLimit:1];

NSError *error;
NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
NSManagedObject *object = [results firstObject];
if (object) {
    // there is at least one object matching you predicate
} else {
    // there is no object matching your predicate in the moc
}

答案 4 :(得分:0)

这是我的尝试。 注: Book Entity继承自NSManagedObject。

NSPredicate *predicate = [NSPredicate predicateWithFormat: @"isbn ==9780786660506"];

Book *book = (Book*) [CoreDataHelper getEntityFromFetchedResultsController:@"Book" :predicate :nil :YES :application.managedObjectContext];


if (book !=nil)    NSLog(@"book entity %@",book.title);

在一个名为CoreDataHelper

的静态助手类中使用它
+ (NSManagedObject*)getEntityFromFetchedResultsController: (NSString*) entityName : (NSPredicate *) predicate : (NSString*) sortKey : (BOOL) sortAscending : (NSManagedObjectContext *) managedObjectContext
{

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[request setEntity:entity]; 
[request setFetchLimit:1];

// If a predicate was passed, pass it to the query
if(predicate != nil)
{
    [request setPredicate:predicate];
}

// If a sort key was passed, use it for sorting.
if(sortKey != nil)
{
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [request setSortDescriptors:sortDescriptors];
    [sortDescriptors release];
    [sortDescriptor release];
}

NSError *error;

NSMutableArray *mutableFetchResults = [[[managedObjectContext executeFetchRequest:request error:&error] mutableCopy] autorelease];


    if (error !=nil){
NSLog(@"error %@", error);
}
   if ([mutableFetchResults count] >0)
    {
   NSManagedObject *firstObject = [mutableFetchResults objectAtIndex:0];
   return firstObject;
    }else
    {
      return nil;
    }

}