1

を使用してデータベースに保存するためのコンテキストでいくつかのエンティティを作成しました

AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];

いくつかのエンティティを追加した後、フローフェッチリクエストを実行します

 NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"AppCalendarEntity"];
   NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;

最初のコマンドを使用してコンテキストで追加したエンティティのみを含む結果が返され、データベースにすでに保存されているエントリは返されません。この段階で、ドキュメントの状態がUIDocumentStateNormalであることを確認しました。

この行をすでに開いているドキュメント(UIDocumentStateNormal)に追加すると、期待される結果が返されます。つまり、dbから結果を取得するだけでなく、まだdbに保存されていないメモリコンテキストも取得します。

[managedDocument openWithCompletionHandler:^(BOOL success) 
     {
       NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"AppCalendarEntity"];
   NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
}

私の質問は1-クエリの結果はどちらの場合も同じになると思います。上記の場合、なぜそうではないのですか。2-ドキュメントの状態がUIDocumentStateNormalの場合、ドキュメントを開くためにコンテキストで「openWithCompletionHandler」を呼び出すべきではありません。この特定のシナリオでは、これを追加した後に望ましい結果が得られる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 ];

    }
4

2 に答える 2

1

UIManagedDocumentを使用する場合、MOCは自動保存を実装しているため、MOCでsaveを呼び出さないでください。ただし、将来のある時点で自動保存を実行する必要があることを伝える必要があります。

  1. その関数でopenWithCompletionHandlerへの呼び出しを削除します(この問題をデバッグするためだけに存在したことはわかっています)。

  2. 交換

    [managedDocument.managedObjectContext save:&InternalError]

[managedDocument updateChangeCount:UIDocumentChangeDone];

これにより、保存できるようになったことをドキュメントに通知します。

編集

まず、デバッグハックを取り除く必要があると思います。NSLogまたはNSAssertを追加できますが、それ以外の部分では、理由がわかりにくくなり、実際の問題が混乱します。

第二に、ここでのあなたの本当の目標は何ですか?メソッドの名前とコードはわかりますが、一致していません。

ここにはたくさんの「がらくた」があり、あなたの問題を理解するのは難しいです。「開いている」ものを削除するための編集とともに、コードを再投稿し、コードコメントとして質問で注釈を付けます。

うまくいけば、この変更が問題の解決に役立つことを願っています。

// 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にあります-それが作成される方法だからです。フェッチを実行すると、保留中の変更を無視して(以前のコメントの1つに記載されているように)、保存された変更のみを受け入れるように検索を強制できます。

保留中の変更を無視する場合は、

fetchRequest.includesPendingChanges = NO;
于 2012-04-18T00:34:15.490 に答える
0

@Jodyの問題は解決されました。この質問に時間を割いていただき、ありがとうございます。

まず、あなたの混乱に対処させてください

1-はい関数はデータベースに保存することを目的としており、補助関数です。この関数に渡されるパラメータ「appCalendarArray」は、コンテキストですでに作成されているエンティティで構成されています。外部APIとの通信、jsonの解析などが含まれるため、意図的にロジックを削除しました。コンテキストにエンティティを挿入するために必要なコードは、質問の最初の部分にすでに含まれています。

AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];

2-一意である必要があるデータベースの列に基づいて、構築されているがまだコンテキストから保存されていないエンティティをコンテキストから削除します。すでにデータベースにオブジェクトの識別子がある場合、それを再保存する必要はありません。だから、私は単にそれを文脈から削除します。この関数は期待どおりに機能し、エンティティはデータベースに再保存されません。最後の行は、コンテキストに残っているオブジェクトがあればそれを保存します。ほとんどの場合、たくさんあります。

3-AppCalendarEntityとMyEntityのタイプを間違えて申し訳ありませんが同じです。

解決


このフラグを追加しましたfetchRequest.includesPendingChanges=NO; 、dbを削除し、Xcodeを再起動すると、動作を開始しました。頑張ってくれてありがとう

于 2012-04-18T20:12:36.640 に答える