Is there any way we can restrict duplicate entries

2020-05-21 12:41发布

问题:

I have been trying to add objects in core data. So, i want that it should not allow duplicate entries in core data store. How to do that? This is my code related to save data.

  -(IBAction)save:(id)sender
    {

        if([name.text isEqualToString:@""] && [address.text isEqualToString:@""] && [phone.text isEqualToString:@""])
        {

            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Yo..!"
                                                        message:@"Data Not Saved"
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
            [alert show];
        }
    else
    {
        coreDataAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

        NSManagedObjectContext *context = [appDelegate managedObjectContext];


        NSManagedObject *newContact;
        newContact = [NSEntityDescription
                      insertNewObjectForEntityForName:@"Contacts"
                      inManagedObjectContext:context];


        [newContact setValue:name.text forKey:@"name"];
        [newContact setValue:address.text forKey:@"address"];
        [newContact setValue:phone.text forKey:@"phone"];


        name.text = @"";
        address.text = @"";
        phone.text = @"";

        NSError *error;
        [context save:&error];

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Yo..!"
                                                    message:@"Data Saved"
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
        [alert show];

         NSLog(@"Object Saved\n");

    }


}

回答1:

As there is no built in method available, you need to fetch results and check whether result contains object you don't want to be duplicated.

Here is code snippet:

-(void)checkForDuplicates
{
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Students"
                                          inManagedObjectContext:managedObjectContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entity];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"students"
                                                               ascending:NO];
    NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

    [request setSortDescriptors:sortDescriptors];
    [sortDescriptor release];

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

   if (!mutableFetchResults) {
        // error handling code.
    }

    if ([[mutableFetchResults valueForKey:@"users"]
         containsObject:name.text]) {
        //notify duplicates
        return;
    }
    else
    {
         //write your code to add data
    }
}

Hope this may help you!



回答2:

no, coredata has no built-in in uniquing as it isn't a DB.


you have to assure uniqueness in your program logic.

e.g. often, one does a fetch for an entry that should be unique and if that fetch has 1 entry, don't add another, else add it!

==> this works well for serial CD access, but can get complicated with multiple contexts that run in a multithreaded env



回答3:

I think the best approach would be to call the countForFetchRequest method using a predicate to evaluate whether your store has a matching object. Since this type of request does not pull back any objects it should be more performant than other solutions. Here is a Swift 2.0 implementation added to a NSManagedObject subclass.

  func tokenExists (aToken:String) -> Bool {
        let request: NSFetchRequest = NSFetchRequest(entityName: self.className!)

        let predicate = NSPredicate(format: "token == %@", argumentArray: [aToken])

        request.predicate = predicate

        let error: NSErrorPointer = nil

        let count = self.managedObjectContext!.countForFetchRequest(request, error: error)

        if count == NSNotFound {
            return false
        }
        return true
    }

NB - (One could substitute any equality criteria you like for the predicate but keep in mind that if possible you should use a numerical identifier if one is available ~ for best performance)

Usage:

One might then use the function above during the insertion:

func insertToken (value:String) {

        if  !tokenExists(value) {
            self.token = value
            saveState()
        }

    }


回答4:

In Core Data there is no such thing as duplicate entries, as least as far as Core Data is concerned. Not in the sense of looking at it from a database point of view. Which makes sense because Core Data is not a database it is an object graph management system.

So to prevent duplicates you need to do a search first then if the search returns NULL only then save, else do nothing.

This article gives you code which you can customise to your needs



回答5:

Let me put the best approach from Apple Sample code itself. Please refer the sample code "ThreadedCoreData" for more info.

https://developer.apple.com/library/content/samplecode/ThreadedCoreData/Introduction/Intro.html

    // before adding the earthquake, first check if there's a duplicate in the backing store
    NSError *error = nil;
    Earthquake *earthquake = nil;
    for (earthquake in earthquakes) {
        fetchRequest.predicate = [NSPredicate predicateWithFormat:@"location = %@ AND date = %@", earthquake.location, earthquake.date];

        NSArray *fetchedItems = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
        if (fetchedItems.count == 0) {
            // we found no duplicate earthquakes, so insert this new one
            [self.managedObjectContext insertObject:earthquake];
        }
    }