Core data NSFetchRequest的意外行为
我在上下文中创建了几个实体,以便使用Core data NSFetchRequest的意外行为,core-data,Core Data,我在上下文中创建了几个实体,以便使用 AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument]; 添加几个实体后,我执行流式提取请求 NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"AppCalendarEnt
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
添加几个实体后,我执行流式提取请求
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"AppCalendarEntity"];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
它返回的结果仅包括我使用第一个命令在上下文中添加的实体,而不包括已保存在数据库中的条目。我已确保在此阶段文档状态为UIDocumentStateNormal
当我将此行添加到已打开的文档(UIDocumentStateNormal)中时,它会返回预期结果,即从数据库中获取结果以及尚未保存到数据库中的内存上下文
[managedDocument openWithCompletionHandler:^(BOOL success)
{
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"AppCalendarEntity"];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
}
我的问题是
1-我希望两种情况下的查询结果应该是相同的。为什么在上述情况下并非如此。
2-对我来说,如果文档状态为UIDocumentStateNormal,我不应该在上下文中调用“openWithCompletionHandler”来打开文档。在这个特定的场景中,添加此项后,NSFetchRequest会给我提供所需的结果,这与NSFetchRequest有什么不同
如果我错了,请告诉我
这是完整的代码
这是函数的完整代码
+ (void ) saveCalendarArrayInDbIfItAlreadyDoesNotExist : (NSArray*) appCalendarArray managedDocument: (UIManagedDocument*) managedDocument completionBlock : ( void(^) (NSArray* ObjectSavedSuccesfully, NSError *InternalError)) handler
{
// i dont know why i have to do it :( if i dont add openWithCompletionHandler my query doesnt fetch result from db rather just do query in-memory context and not db
[managedDocument openWithCompletionHandler:^(BOOL success)
{
void (^completionHandler)(NSArray* , NSError* );
completionHandler = [handler copy ];
NSError *error = nil;
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id appCalendar in appCalendarArray) {
if([appCalendar isKindOfClass:[AppCalendarEntity class]])
{
AppCalendarEntity *appCalendarEntity = (AppCalendarEntity*) appCalendar;
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"MyEntity"];
requestToSeeIfCalendarWithIdExist.predicate = [NSPredicate predicateWithFormat:@"identifier = %@", appCalendarEntity.identifier];
NSError *InternalError = nil;
[requestToSeeIfCalendarWithIdExist setShouldRefreshRefetchedObjects:YES];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
// "result" is different when we encapsulate it in openWithCompletionHandler and when we don't…….MY PROBLEM
if(result == nil)
{
// return error
}
// 1 object always return that depict the in memory(context) object we created but not saved. I expect it should be zero because no object has yet been saved to database..
else if(result.count > 1)
{
[managedDocument.managedObjectContext deleteObject:appCalendar];
}
else
{
[array addObject:appCalendarEntity];
}
}
else
{
// error handling
}
}
if (error != nil)
{
completionHandler (nil, error);
return;
}
// saving all the objects
[ managedDocument updateChangeCount:UIDocumentChangeDone ];
}
使用UIManagedDocument时,不要在MOC上调用save,因为它实现了自动保存。但是,需要告知的是,自动保存应该在将来的某个时候进行
// First, the method name seems to indicate that some objects will be added
// to the database. however, the only database work in this method is removal.
// I don't get it.
+ (void ) saveCalendarArrayInDbIfItAlreadyDoesNotExist : (NSArray*) appCalendarArray managedDocument: (UIManagedDocument*) managedDocument
{
NSError *error = nil;
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id appCalendar in appCalendarArray) {
if([appCalendar isKindOfClass:[AppCalendarEntity class]]) {
// OK, we are filtering the array of objects. We are only interested in
// objects of type AppCalendarEntity, and are going to use its identity
// property to look for objects of type MyEntity.
// What is the relationship between AppCalendarEntity and MyEntity?
AppCalendarEntity *appCalendarEntity = (AppCalendarEntity*) appCalendar;
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"MyEntity"];
requestToSeeIfCalendarWithIdExist.predicate = [NSPredicate predicateWithFormat:@"identifier = %@", appCalendarEntity.identifier];
NSError *InternalError = nil;
[requestToSeeIfCalendarWithIdExist setShouldRefreshRefetchedObjects:YES];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError];
// OK, now we just got a result from searching for a MyEntity, where
// its identifier is the same as the appCalendarEntity.
if(result == nil)
{
// return error
}
// 1 object always return that depict the in memory(context) object we created but not saved. I expect it should be zero because no object has yet been saved to database..
else if(result.count > 1)
{
// I am extremely confused by this code. First, why are you
// checking for more than 1 object? The method name indicates
// you are going to insert something. Furthermore, you are only
// deleting one object. How many do you expect? Also, why are
// you deleting an appCalendar? You were searching for a MyEntity.
// If an appCalendar is a MyEntity, then that's terrible naming.
// Furthermore, it would explain why you are finding it...
// because you create entities by inserting them in a MOC to
// begin with!
[managedDocument.managedObjectContext deleteObject:appCalendar];
}
else
{
// Even more confusion. You are adding this object to an internal
// array, not the database. Furthermore, you are doing it if there
// are either 0 or 1 MyEntity objects in the database with matching
// identifier.
[array addObject:appCalendarEntity];
}
}
}
// saving all the objects
// OK - but the only thing being saved are the ones you deleted...
[ managedDocument updateChangeCount:UIDocumentChangeDone ];
}
最后,如果我的直觉是正确的,日历对象实际上是MyEntity对象,它们已经在MOC中了——因为它们就是这样创建的。在执行提取时,可以强制搜索忽略挂起的更改(如我前面的一条评论中所述),而只接受保存的更改
如果要忽略挂起的更改
fetchRequest.includesPendingChanges = NO;
使用UIManagedDocument时,不要在MOC上调用save,因为它实现了自动保存。但是,需要告知的是,自动保存应该在将来的某个时候进行
// First, the method name seems to indicate that some objects will be added
// to the database. however, the only database work in this method is removal.
// I don't get it.
+ (void ) saveCalendarArrayInDbIfItAlreadyDoesNotExist : (NSArray*) appCalendarArray managedDocument: (UIManagedDocument*) managedDocument
{
NSError *error = nil;
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id appCalendar in appCalendarArray) {
if([appCalendar isKindOfClass:[AppCalendarEntity class]]) {
// OK, we are filtering the array of objects. We are only interested in
// objects of type AppCalendarEntity, and are going to use its identity
// property to look for objects of type MyEntity.
// What is the relationship between AppCalendarEntity and MyEntity?
AppCalendarEntity *appCalendarEntity = (AppCalendarEntity*) appCalendar;
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"MyEntity"];
requestToSeeIfCalendarWithIdExist.predicate = [NSPredicate predicateWithFormat:@"identifier = %@", appCalendarEntity.identifier];
NSError *InternalError = nil;
[requestToSeeIfCalendarWithIdExist setShouldRefreshRefetchedObjects:YES];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError];
// OK, now we just got a result from searching for a MyEntity, where
// its identifier is the same as the appCalendarEntity.
if(result == nil)
{
// return error
}
// 1 object always return that depict the in memory(context) object we created but not saved. I expect it should be zero because no object has yet been saved to database..
else if(result.count > 1)
{
// I am extremely confused by this code. First, why are you
// checking for more than 1 object? The method name indicates
// you are going to insert something. Furthermore, you are only
// deleting one object. How many do you expect? Also, why are
// you deleting an appCalendar? You were searching for a MyEntity.
// If an appCalendar is a MyEntity, then that's terrible naming.
// Furthermore, it would explain why you are finding it...
// because you create entities by inserting them in a MOC to
// begin with!
[managedDocument.managedObjectContext deleteObject:appCalendar];
}
else
{
// Even more confusion. You are adding this object to an internal
// array, not the database. Furthermore, you are doing it if there
// are either 0 or 1 MyEntity objects in the database with matching
// identifier.
[array addObject:appCalendarEntity];
}
}
}
// saving all the objects
// OK - but the only thing being saved are the ones you deleted...
[ managedDocument updateChangeCount:UIDocumentChangeDone ];
}
最后,如果我的直觉是正确的,日历对象实际上是MyEntity对象,它们已经在MOC中了——因为它们就是这样创建的。在执行提取时,可以强制搜索忽略挂起的更改(如我前面的一条评论中所述),而只接受保存的更改
如果要忽略挂起的更改
fetchRequest.includesPendingChanges = NO;
@Jody的问题已经解决了,感谢您抽出时间回答这个问题
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
首先让我谈谈你的困惑
1-是功能旨在保存在数据库中,它是一个帮助功能。传递给此函数的参数“appCalendarArray”由已在上下文中创建的实体组成。我故意消除了逻辑,因为它涉及与外部API通信、解析json等。在上下文中插入实体所需的代码已经包含在问题的第一部分中
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
2-我根据数据库中应该是唯一的列,从上下文中删除已构建但尚未从上下文中保存的实体。若数据库中已有对象的标识符,则不希望重新保存它。所以,我只是从上下文中删除它。此函数按预期工作,实体不会重新保存在数据库中。最后一行不保存保留在上下文中的对象(如果有)。大多数时候都有很多
3-很抱歉输入错误AppCalendarEntity和MyEntity是相同的
解决方案
我已添加此标志fetchRequest.includesPendingChanges=NO,删除数据库,重新启动Xcode,它开始工作。感谢您的坚持@Jody问题已经解决,感谢您抽出时间回答这个问题
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
首先让我谈谈你的困惑
1-是功能旨在保存在数据库中,它是一个帮助功能。传递给此函数的参数“appCalendarArray”由已在上下文中创建的实体组成。我故意消除了逻辑,因为它涉及与外部API通信、解析json等。在上下文中插入实体所需的代码已经包含在问题的第一部分中
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
2-我从contex中删除实体