2

ContainerエンティティとItemエンティティを持つCoreDataモデルがあります。コンテナには、0個以上のアイテムを含めることができます。アイテムは少なくとも1つのコンテナに属している必要があります(ただし、複数のコンテナに含まれている場合があります)。

関係は次のようになります。

Container:
  Relationship: items, Destination: Item, Inverse: itemContainers
  Optional, To-Many Relationship
  Delete Rule: Nullify

Item:
  Relationship: itemContainers, Destination: Container, Inverse: items
  Not-Optional, To-Many Relationship
  Delete Rule: Cascade

コンテナを削除すると問題が発生します。そのコンテナ内のItemオブジェクトは更新されますが、アイテムが1つのコンテナにのみ存在する場合、itemContainersプロパティはオブジェクトのないセットになります。その空のセットがitemContainersのItemのオプションではない設定に違反しているため、オブジェクトグラフの保存は失敗します。

もちろん、「itemContainers。@ count == 0」のようなNSPredicateを使用して、空のitemContainersを持つItemオブジェクトを見つけるのは簡単ですが、これを自動的に行うようにモデルを構成する方法があるはずです。

それで、より簡単でより良い方法はありますか?

4

5 に答える 5

4

上記のTonyArnoldの回答を同様の問題で試しましたが、複数の「コンテナ」を一度に削除すると問題が見つかりました(これはOS X 10.8.2にあります)。コンテナーは[item itemContainers]、管理対象オブジェクトのコンテキストが保存されるまで削除されないため、count1より上に留まり、item削除されることはありません。

-[NSManagedObject isDeleted]でおよびカテゴリメソッドを使用して、次のソリューションを考え出しましたNSManagedObject

ファイルNSManagedObject+RJSNondeletedObjects.h

#import <CoreData/CoreData.h>

@interface NSManagedObject (RJSNondeletedObjects)

- (NSSet *)RJS_nondeletedObjectsForToManyKeyPath:(NSString *)keyPath;
- (BOOL)RJS_hasOtherNondeletedObjectsForToManyKeyPath:(NSString *)keyPath;

@end

ファイルNSManagedObject+RJSNondeletedObjects.m

#import "NSManagedObject+RJSNondeletedObjects.h"

@implementation NSManagedObject (RJSNondeletedObjects)

- (NSSet *)RJS_nondeletedObjectsForToManyKeyPath:(NSString *)keyPath
{
    NSSet * result = nil;

    id allObjectsForKeyPath = [self valueForKeyPath:keyPath];

    if ( ![allObjectsForKeyPath isKindOfClass:[NSSet class]] ) return result;

    result = [(NSSet *)allObjectsForKeyPath objectsPassingTest:^BOOL(id obj, BOOL *stop)
    {
        BOOL testResult = ![obj isDeleted];
        return testResult;
    }];

    return result;
}

- (BOOL)RJS_hasOtherNondeletedObjectsForToManyKeyPath:(NSString *)keyPath
{
    BOOL result = NO;

    // self will be in the set of nondeleted objects, assuming it's not deleted. So we need to adjust the test threshold accordingly.
    NSUInteger threshold = [self isDeleted] ? 0 : 1;
    NSSet * nondeletedObjects = [self RJS_nondeletedObjectsForToManyKeyPath:keyPath];
    result = ( [nondeletedObjects count] > threshold );

    return result;
}

@end

Containerクラス

...
#import "NSManagedObject+RJSNondeletedObjects.h"
...
- (void)prepareForDeletion
{
    NSSet *childItems = [self items];

    for (Item *item in childItems) {
        if ([item RJS_hasOtherNondeletedObjectsForToManyKeyPath:@"containers"]) {
            continue;
        }

        [managedObjectContext deleteObject:item];
    }
}
于 2012-11-28T02:20:28.680 に答える
1

Core Dataが提供する構成オプションほどクリーンではないことはわかっていますが、オブジェクトが削除されたときに子エンティティContainerを循環し、オブジェクトが0 ('Container.m'内)であるかどうかを確認するプロジェクトをいくつか展開しました。ItemitemContainers

- (void)prepareForDeletion
{
    NSSet *childItems = [self items];

    for (Item *item in childItems) {
        if ([[item itemContainers] count] > 1) {
            continue;
        }

        [managedObjectContext deleteObject:item];
    }
}
于 2012-04-20T21:50:48.690 に答える
0

私のアプリでは、アイテムのコンテナー関係をオプションにし、「スマートコンテナー」を介してそれらのコンテナーのないアイテムへのアクセスを許可します。

それを望まない場合は、保存の失敗を処理し、違反しているオブジェクトを削除するだけでよいと思います。

コアデータへのアプローチを防御的なものに変更することがますます増えています。検証が失敗すると想定し、それを処理する準備をしています。iCloud同期を統合するとさらに重要になります。

于 2012-04-20T21:52:52.283 に答える
0

モデルでこの動作を指定することはできないと思いますが、そのフェッチを行う代わりにitemContainers、コンテナのカウントを検証することができます。

 - (void)removeItemObject:(Item *)value
{...
if(![[value itemContainers]count])
  [context deleteObject:value];
...
}
于 2012-04-22T06:31:35.953 に答える
0

私はそれをこのようにするのが好きです:

- (void)didChangeValueForKey:(NSString *)inKey withSetMutation:(NSKeyValueSetMutationKind)inMutationKind usingObjects:(NSSet *)inObjects
{
    [super didChangeValueForKey:inKey withSetMutation:inMutationKind usingObjects:inObjects];

    if ([inKey isEqualToString:@"YOURRELATIONSHIP"] && self.YOURRELATIONSHIP.count == 0) {
        [self.managedObjectContext deleteObject:self];
    }
}
于 2013-04-15T14:12:12.527 に答える