mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-01-12 17:43:34 +08:00
Make deletion of newly inserted objects that fail validation configurable. closes #1281
This commit is contained in:
@@ -177,6 +177,19 @@
|
||||
*/
|
||||
- (RKConnectionDescription *)connectionForRelationship:(id)relationshipOrName;
|
||||
|
||||
///-----------------------------
|
||||
/// @name Configuring Validation
|
||||
///-----------------------------
|
||||
|
||||
/**
|
||||
A Boolean value that determines if newly created `NSManagedObject` instances mapped with the receiver should be discarded when they fail `validateForInsert:`.
|
||||
|
||||
This property allows for the deletion of managed objects that fail validation such that `NSManagedObjectContext` save will complete successfully. Typically an invalid managed object in the graph will result in a failure to save the `NSManagedObjectContext` due to an NSValidation error. In some cases it is desirable to persist only the subset of objects that pass validation and discard the invalid content rather than failing the entire operation. Setting this property to `YES` will result in the deletion of in any newly created `NSManagedObject` instances that fail to return `YES` when sent the `validateForInsert:` message.
|
||||
|
||||
**Default**: `NO`
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL discardsInvalidObjectsOnInsert;
|
||||
|
||||
///------------------------------------
|
||||
/// @name Flagging Objects for Deletion
|
||||
///------------------------------------
|
||||
|
||||
@@ -164,6 +164,7 @@ static BOOL entityIdentificationInferenceEnabled = YES;
|
||||
self = [self initWithClass:objectClass];
|
||||
if (self) {
|
||||
self.entity = entity;
|
||||
self.discardsInvalidObjectsOnInsert = NO;
|
||||
if ([RKEntityMapping isEntityIdentificationInferenceEnabled]) self.identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -313,9 +313,10 @@ extern NSString * const RKObjectMappingNestingAttributeKeyName;
|
||||
- (BOOL)commitChangesForMappingOperation:(RKMappingOperation *)mappingOperation error:(NSError **)error
|
||||
{
|
||||
if ([mappingOperation.objectMapping isKindOfClass:[RKEntityMapping class]]) {
|
||||
[self emitDeadlockWarningIfNecessary];
|
||||
[self emitDeadlockWarningIfNecessary];
|
||||
|
||||
NSArray *connections = [(RKEntityMapping *)mappingOperation.objectMapping connections];
|
||||
RKEntityMapping *entityMapping = (RKEntityMapping *)mappingOperation.objectMapping;
|
||||
NSArray *connections = [entityMapping connections];
|
||||
if ([connections count] > 0 && self.managedObjectCache == nil) {
|
||||
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Cannot map an entity mapping that contains connection mappings with a data source whose managed object cache is nil." };
|
||||
NSError *localError = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorNilManagedObjectCache userInfo:userInfo];
|
||||
@@ -330,11 +331,11 @@ extern NSString * const RKObjectMappingNestingAttributeKeyName;
|
||||
*/
|
||||
NSOperationQueue *operationQueue = self.operationQueue ?: [NSOperationQueue currentQueue];
|
||||
__weak NSManagedObjectContext *weakContext = [(NSManagedObject *)mappingOperation.destinationObject managedObjectContext];
|
||||
NSBlockOperation *deletionOperation = [NSBlockOperation blockOperationWithBlock:^{
|
||||
NSBlockOperation *deletionOperation = entityMapping.discardsInvalidObjectsOnInsert ? [NSBlockOperation blockOperationWithBlock:^{
|
||||
[weakContext performBlockAndWait:^{
|
||||
RKDeleteInvalidNewManagedObject(mappingOperation.destinationObject);
|
||||
}];
|
||||
}];
|
||||
}] : nil;
|
||||
|
||||
// Add a dependency on the parent operation. If we are being mapped as part of a relationship, then the assignment of the mapped object to a parent may well fulfill the validation requirements. This ensures that the relationship mapping has completed before we evaluate the object for deletion.
|
||||
if (self.parentOperation) [deletionOperation addDependency:self.parentOperation];
|
||||
|
||||
@@ -1373,6 +1373,7 @@
|
||||
NSDictionary *representation = @{ @"human": @{ @"name": @"Blake Watters", @"favoriteCatID": @(12345) }, @"cat": @{ @"railsID": @(12345) } };
|
||||
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat"
|
||||
inManagedObjectStore:managedObjectStore];
|
||||
catMapping.discardsInvalidObjectsOnInsert = YES;
|
||||
RKCat *cat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectContext];
|
||||
RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:cat mapping:catMapping];
|
||||
NSOperationQueue *operationQueue = [NSOperationQueue new];
|
||||
|
||||
@@ -1042,10 +1042,11 @@ NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths);
|
||||
expect(fetchedObjects).to.haveCountOf(1);
|
||||
}
|
||||
|
||||
- (void)testManagedObjectRequestOperationCompletesAndIgnoresInvalidObjects
|
||||
- (void)testManagedObjectRequestOperationCompletesAndIgnoresInvalidObjectsWhenDiscardsInvalidObjectsOnInsertIsYES
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:@"Post" inManagedObjectStore:managedObjectStore];
|
||||
postMapping.discardsInvalidObjectsOnInsert = YES;
|
||||
[postMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"posts" statusCodes:[NSIndexSet indexSetWithIndex:200]];
|
||||
|
||||
@@ -1057,6 +1058,23 @@ NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths);
|
||||
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
|
||||
}
|
||||
|
||||
- (void)testManagedObjectRequestOperationFailsWithValidationErrorWhenDiscardsInvalidObjectsOnInsertIsNO
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:@"Post" inManagedObjectStore:managedObjectStore];
|
||||
postMapping.discardsInvalidObjectsOnInsert = NO;
|
||||
[postMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"posts" statusCodes:[NSIndexSet indexSetWithIndex:200]];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/posts_with_invalid.json" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
|
||||
[managedObjectRequestOperation start];
|
||||
expect(managedObjectRequestOperation.error).notTo.beNil();
|
||||
expect([managedObjectRequestOperation.error code]).to.equal(NSValidationMissingMandatoryPropertyError);
|
||||
expect([managedObjectRequestOperation.error localizedDescription]).to.equal(@"The operation couldn’t be completed. (Cocoa error 1570.)");
|
||||
}
|
||||
|
||||
- (void)testThatSuccessfulCompletionSavesManagedObjectIfTargetObjectIsUnsavedEvenIfNoMappingWasPerformed
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
|
||||
Reference in New Issue
Block a user