Core Data fetching data and looking for duplicate - ios

I want to fetch data from Core data and look for duplicats and then only save the data then there is no duplicate of the movieid.
Maybe some one can help me ..
How can I compare the result with the movieid string ?
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "MovieData")
//request.predicate = NSPredicate(format: "movieid = %#", movieID)
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "movieid") as! String)
}
} catch {
print("Failed")
}

Almost. Apply the predicate to get only the record with the specific movieID. However it assumes that movieID is an object (NSNumber), if it's an scalar Int you have to use %ld as placeholder.
If the fetch returns an empty array there is no duplicate and you can insert a new object
let request = NSFetchRequest<NSManagedObject>(entityName: "MovieData")
request.predicate = NSPredicate(format: "movieid = %#", movieID)
do {
let result = try context.fetch(request)
if result.isEmpty {
let newMovie = NSEntityDescription.insertNewObject(forEntityName: "MovieData", into: context) as! MovieData
newMovie.movieid = movieID
try context.save()
}
} catch {
print(error)
}

While saving in core data you need to create predicate and in there you need to check if there are values already saved with same "movieid" then it has to be updated , this way you won't have duplicate data . Please refer the method and try using the same for saving the values in DB . This way duplicate values won't be saved in DB
class func insertupdaterecord (movieID:String, context: NSManagedObjectContext)
{
let entityDescription = NSEntityDescription.entity(forEntityName: "movie", in: context)
let pred = NSPredicate(format: "movieid = %#", movieID)
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "movie")
fetchRequest.entity = entityDescription
fetchRequest.predicate = pred
let result = try! (context.fetch(fetchRequest) as NSArray).lastObject
let updateInsertInfo : movie
if result != nil
{
updateInsertInfo = result as! movie
}
else
{
print("Record not found!")
}
do
{
try context.save()
}
catch let error as NSError
{
print("Error while saving \(error) in database.")
}
}

Create a cache for movieid values to check for duplicates and loop through the fetched result and delete any objects with a movieid already in the cache and then save once the loop is done.
var selection: [String] = []
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "MovieData")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
guard let movieId = data.value(forKey: "movieid") as? String else {
context.delete(data) // or however you want to handle this situation
continue
}
if selection.contains(movieId) {
context.delete(data)
} else {
selection.append(movieId)
}
}
try context.save()
} catch {
print("Failed")
}

Related

How to get specfic data of row as dictionary by search in coredata

i had added this code for search via product_id in coredata but that returns all records i want to just get specific data from row that contain that product_id
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "CartEntity")
let predicate = NSPredicate(format: "product_id == %#", "\(Product_id)")
request.predicate = predicate
request.fetchLimit = 1
do{
let count = try managedContext.count(for: request)
if(count == 0){
// no matching object
print("no")
self.savecoredata()
}
else{
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "CartEntity")
request.returnsObjectsAsFaults = false
do {
let result = try managedContext.fetch(request)
for dataresult in result as! [NSManagedObject] {
let userName = dataresult.value(forKey: "proname") as! String
let age = dataresult.value(forKey: "price") as! String
print("User Name is : "+userName+" and price is : "+age)
print(datastored)
}
} catch {
print("Fetching data Failed")
}
print("yes")
// deleteFeed(id: "\(Product_id)")
// first delete old and than insert new id
}
}
catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
The problem is that you have to different requests, first you use one with a predicate and then you use one without a predicate which will return all rows. Either reuse the predicate for the second request as well or even better skip the first count request that seems unnecessary and perform only the second one
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "CartEntity")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "product_id == %#", "\(Product_id)")
do {
let result = try managedContext.fetch(request)
for dataresult in result as! [NSManagedObject] {
//... rest of code
First of all use the predicate of the first request and secondly use a specific fetch request to return the actual NSManagedObject subclass. The benefit is to get the values directly with dot notation rather than with error-prone KVC (key-value coding).
This is the corresponding logic of your entire code, however the savecoredata line seems to be pointless
let request : NSFetchRequest<CartEntity> = CartEntity.fetchRequest()
request.predicate = NSPredicate(format: "product_id == %ld", Product_id)
do {
if let result = try managedContext.fetch(request).first {
let userName = result.proname
let price = result.price
print("User Name is : \(userName) and price is : \(price)")
} else {
// no matching object
print("no")
self.savecoredata()
}
} catch {
print(error)
}
The issue seems to be with your predicate. Check if the product_id is string or integer. If you are doing casting then apply format "%d", "%ld"
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "CartEntity")
let predicate = NSPredicate(format: "product_id = \(Product_id)")
request.predicate = predicate
request.fetchLimit = 1
var count = 0
do{
count = try managedContext.count(for: request)
}
catch let error {
print("Could not fetch \(error), \(error.localizedDescription)")
}
guard count != 0 else {
// no matching object
print("no")
self.savecoredata()
return
}
// remove predicate, which is actually not required.
request.predicate = nil
request.returnsObjectsAsFaults = false
do {
let result = try managedContext.fetch(request)
for dataresult in result as! [NSManagedObject] {
let userName = dataresult.value(forKey: "proname") as! String
let age = dataresult.value(forKey: "price") as! String
print("User Name is : "+userName+" and price is : "+age)
print(datastored)
}
} catch let error {
print("Fetching data Failed - \(error)")
}
print("yes")
// deleteFeed(id: "\(Product_id)")
// first delete old and than insert new id

Why are my CoreData updates not persisting when I relaunch the app?

I'm trying to edit a value in a previously saved object in CoreData.
The object appears to have been updated, until I relaunch the app, and the value is now set to 'nil'.
Here is my method for saving the changes:
class SaveNewQuickShareTrip: NSManagedObject {
static func addNewTrip(_ username: String, newTrip: TripModel, tripType : String, in context: NSManagedObjectContext) {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: Constants.User)
request.predicate = NSPredicate(format: "username=%#", username)
request.returnsObjectsAsFaults = false
var currentTrips : [TripModel] = Array<TripModel>()
do {
let matches = try context.fetch(request)
if matches.count == 1 {
for userData in matches as! [NSManagedObject] {
currentTrips = userData.value(forKey: tripType) as! Array<TripModel>
print("currentTrips OLD count = ", currentTrips.count)
currentTrips.append(newTrip)
userData.setValue(currentTrips, forKey: Constants.quickShareTrips)
print("currentTrips NEW count = ", currentTrips.count)
}
do {
try context.save()
} catch {
print("Saving the new trip failed!")
}
}
} catch {
print("Something went wrong when saving the quick share trip.")
}
}
}
And code I'm using to retrieve the object upon launch:
class UserRetrieval: NSManagedObject {
static func fetchUser(_ username: String, in context: NSManagedObjectContext) -> [NSManagedObject] {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: Constants.User)
request.predicate = NSPredicate(format: "username=%#", username)
request.returnsObjectsAsFaults = false
var theUser = [NSManagedObject]()
do {
let matches = try context.fetch(request)
if let records = matches as? [NSManagedObject] {
theUser = records
}
} catch {
print("Can't find User.")
}
return theUser
}
}

Update core data object swift 3

I want to update a core data object in swift 3. After some googled I didn't found anything about swift 3.
So my question is: how can I update a core data object in swift 3?
Fetch the existing values using a fetch request with a predicate. Use a unique value in the predicate. Once you've fetched the object, update the object with new values and save the context.
let empId = "001"
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "EmpDetails")
let predicate = NSPredicate(format: "empId = '\(empId)'")
fetchRequest.predicate = predicate
do {
let result = try persistentContainer.viewContext.fetch(fetchRequest)
if let objectToUpdate = result.first as? NSManagedObject {
objectToUpdate.setValue("newName", forKey: "name")
objectToUpdate.setValue("newDepartment", forKey: "department")
objectToUpdate.setValue("001", forKey: "empID")
try persistentContainer.viewContext.save()
}
} catch {
print(error)
}
Using NSManagedObject subclass
let empId = "001"
let fetchRequest: NSFetchRequest<Employee> = Employee.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "%K = %#", #keyPath(Employee.id), empId)
do {
let results = try persistentContainer.viewContext.fetch(fetchRequest)
if let employee = results.first {
employee.name = "new name"
employee.department = "new department"
}
try persistentContainer.viewContext.save()
} catch let error as NSError {
print(error.localizedDescription)
}
Batch updates
Batch updates help to update multiple Core Data objects without having
to fetch anything into memory.
let batchUpdate = NSBatchUpdateRequest(entityName: "Employee")
batchUpdate.propertiesToUpdate = [#keyPath(Employee.isActive): true]
batchUpdate.affectedStores = persistentContainer.viewContext.persistentStoreCoordinator?.persistentStores
batchUpdate.resultType = .updatedObjectsCountResultType
do {
let batchResult = try coreDataStack.managedContext.execute(batchUpdate) as? NSBatchUpdateResult
print(batchResult?.result)
} catch let error as NSError {
print(error.localizedDescription)
}
Pass unique id in variable "id"(Unique variable created in Core data model) and all the variable as you want to update values:
func context() -> NSManagedObjectContext {
let context=(UIApplication.shared.delegate as!AppDelegate).persistentContainer.viewContext
return context
}
func save() {
(UIApplication.shared.delegate as! AppDelegate).saveContext()
}
func UpdateCartByTestId(id:Int64,name:String) {
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Update")
fetchRequest.returnsObjectsAsFaults = false
fetchRequest.predicate = NSPredicate(format:"id == %d",id)
let result = try? context().fetch(fetchRequest)
if result?.count == 1 {
let dic = result![0]
dic.setValue(id, forKey: "id")
dic.setValue(name, forKey: "name")
save()
}
}

Swift 3 Core Data Delete Object

Unfortunately the new Core Data semantics make me crazy. My previous question had a clean code that didn't work because of incorrect auto generation of header files. Now I continue my work with deleting objects.
My code seems to be very simple:
func deleteProfile(withID: Int) {
let fetchRequest: NSFetchRequest<Profile> = Profile.fetchRequest()
fetchRequest.predicate = Predicate.init(format: "profileID==\(withID)")
let object = try! context.fetch(fetchRequest)
context.delete(object)
}
I did a "hard" debug with print(object) instead of context.delete(object) and it showed me the right object.
So I need just to delete it.
P.S. there is no deleteObject. Now NSManagedContext has only public func delete(_ sender: AnyObject?)
The result of a fetch is an array of managed objects, in your case
[Event], so you can enumerate the array and delete all matching objects.
Example (using try? instead of try! to avoid a crash in the case
of a fetch error):
if let result = try? context.fetch(fetchRequest) {
for object in result {
context.delete(object)
}
}
do {
try context.save()
} catch {
//Handle error
}
If no matching objects exist then the fetch succeeds, but the resulting
array is empty.
Note: In your code, object has the type [Event] and therefore in
context.delete(object)
the compiler creates a call to the
public func delete(_ sender: AnyObject?)
method of NSObject instead of the expected
public func delete(_ object: NSManagedObject)
method of NSManagedObjectContext. That is why your code compiles
but fails at runtime.
The trick here, it is save context after deleting your objects.
let fetchRequest: NSFetchRequest<Profile> = Profile.fetchRequest()
fetchRequest.predicate = Predicate.init(format: "profileID==\(withID)")
let objects = try! context.fetch(fetchRequest)
for obj in objects {
context.delete(obj)
}
do {
try context.save() // <- remember to put this :)
} catch {
// Do something... fatalerror
}
I hope this can help someone.
func deleteRecords() {
let delegate = UIApplication.shared.delegate as! AppDelegate
let context = delegate.persistentContainer.viewContext
let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "nameofentity")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
do {
try context.execute(deleteRequest)
try context.save()
} catch {
print ("There was an error")
}
}
Delete core data objects swift 3
// MARK: Delete Data Records
func deleteRecords() -> Void {
let moc = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
let result = try? moc.fetch(fetchRequest)
let resultData = result as! [Person]
for object in resultData {
moc.delete(object)
}
do {
try moc.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
// MARK: Get Context
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
Swift 4.1, 4.2 and 5.0
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let requestDel = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
requestDel.returnsObjectsAsFaults = false
// If you want to delete data on basis of some condition then you can use NSPredicate
// let predicateDel = NSPredicate(format: "age > %d", argumentArray: [10])
// requestDel.predicate = predicateDel
do {
let arrUsrObj = try context.fetch(requestDel)
for usrObj in arrUsrObj as! [NSManagedObject] { // Fetching Object
context.delete(usrObj) // Deleting Object
}
} catch {
print("Failed")
}
// Saving the Delete operation
do {
try context.save()
} catch {
print("Failed saving")
}
Swift 4 without using string for Entity
let fetchRequest: NSFetchRequest<Profile> = Profile.fetchRequest()
fetchRequest.predicate = Predicate.init(format: "profileID==\(withID)")
do {
let objects = try context.fetch(fetchRequest)
for object in objects {
context.delete(object)
}
try context.save()
} catch _ {
// error handling
}
Delete Core Data Object with query in Swift 5, 4.2
let fetchRequest = NSFetchRequest<Your_Model>(entityName: "Your_Entity_Name")
fetchRequest.predicate = NSPredicate(format: "any your_key == %d", your_value)
hope this will help to someone
Swift 5
Common function for Deleting core data objects for any anity swift 5
func deleteEntityObjectByKeyValue<T>(className: T.Type, key: String, value: Any) -> Bool {
let context = CoreDataStack.sharedStack.mainContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: className.self))
//Search based on data type.I used for Int and String
if let sValue = value as? String {
let predicate = NSPredicate(format: "\(key) == %#", sValue)
fetchRequest.predicate = predicate
} else if let iValue = value as? Int64 {
let predicate = NSPredicate(format: "\(key) == %d", iValue)
fetchRequest.predicate = predicate
}
do {
let result = try context.fetch(fetchRequest)
if result.count != 0 {
if let managedObject = result[0] as? NSManagedObject {
context.delete(managedObject)
do {
try context.save()
return true
}
catch let error {
print(error.localizedDescription)
}
}
}
return false
} catch let error {
print(error.localizedDescription)
}
return false
}
How To Use it:
let isSaved = CoreDataOperations.shared.deleteEntityObjectByKeyValue(className: EmpolyeeData.self, key: "employeeId", value:1234)
If isSaved {
print("Deleted obj Successfully")
}
Swift 4,5
It is useful to delete particular record or all records from entity.
1.Create a NSPersistentContainer and NSManagedObjectContext using below code.
class CoreDataStack: NSObject {
static var sharedStack = CoreDataStack()
private override init() {}
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Employee")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let url = storeDescription.url {
print("SQLITE STORE LOCATION: \(url.absoluteString)")
}
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.shouldDeleteInaccessibleFaults = true
container.viewContext.automaticallyMergesChangesFromParent = true
return container
}()
private lazy var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
private lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = Bundle.main.url(forResource: "____", withExtension: "____")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
public lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("Employee" + ".sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
let options = [ NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
}
return coordinator
}()
lazy var mainContext: NSManagedObjectContext = {
var managedObjectContext: NSManagedObjectContext?
if #available(iOS 10.0, *){
managedObjectContext = self.persistentContainer.viewContext
managedObjectContext?.mergePolicy = NSMergePolicy.init(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
}
else{
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext?.persistentStoreCoordinator = coordinator
managedObjectContext?.mergePolicy = NSMergePolicy.init(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
}
return managedObjectContext!
}()
}
2.Common function for Deleting core data all objects for any Entity swift 5
func deleteEntityData(entity : String) {
let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
do {
try CoreDataStack.sharedStack.mainContext.execute(deleteRequest)
CoreDataStack.sharedStack.saveMainContext()
} catch {
print ("There was an error")
}
}
3.How to use above code.
self.deleteEntityData(entity : "Employee")
4.If you want to delete Particular object from Entity
func deleteEntityObjectByKeyValue<T>(entityName: T.Type, key: String, value: Any) -> Bool {
let context = CoreDataStack.sharedStack.mainContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: entityName.self))
if let sValue = value as? String {
let predicate = NSPredicate(format: "\(key) == %#", sValue)
fetchRequest.predicate = predicate
} else if let iValue = value as? Int64 {
let predicate = NSPredicate(format: "\(key) == %d", iValue)
fetchRequest.predicate = predicate
}
do {
let result = try context.fetch(fetchRequest)
if result.count != 0 {
if let managedObject = result[0] as? NSManagedObject {
context.delete(managedObject)
do {
CoreDataStack.sharedStack.saveMainContext()
return true
}
catch let error {
print(error.localizedDescription)
}
}
}
return false
} catch let error {
print(error.localizedDescription)
}
return false
}
Delete the object from core data
let entity = NSEntityDescription.entity(forEntityName: "Students", in: managedContext)
let request = NSFetchRequest<NSFetchRequestResult>()
request.entity = entity
if let result = try? managedContext.fetch(request) {
for object in result {
managedContext.delete(object as! NSManagedObject)
}
txtName.text = ""
txtPhone.text = ""
txt_Address.text = ""
labelStatus.text = "Deleted"
}

How to store one value using core-data ? (swift 2)

I'm developing an app to store one phone number at time using core data, the user should be able to enter a new phone number into ui text field,if it's equal to nil, it should store a new phone number,else it should replace old number with new number; it should store only one value.
but the code doesn't work as it should
what's wrong in my code?
let moContext: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = moContext.managedObjectContext
let phoneNu = NSEntityDescription.insertNewObjectForEntityForName("Setting", inManagedObjectContext: context)
let fetchRequest = NSFetchRequest(entityName: "Setting")
fetchRequest.predicate = NSPredicate(format: "phoneNumber = %#", phoneNumber)
// phoneNu.setValue(phoneNumber.text, forKey: "phoneNumber")
do{
let request = NSFetchRequest(entityName: "Setting")
let phoneN = try context.executeFetchRequest(request)
if phoneN.count == 0{
phoneNu.setValue(phoneNumber.text, forKey: "phoneNumber")
}else if phoneN.count != 0{
for item in phoneN as! [NSManagedObject]{
let number = item.valueForKey("phoneNumber")
number?[0]?.setValue(phoneNumber.text, forKey: "phoneNumber")
}
}
}catch{
print("error")
}
do{
let request = NSFetchRequest(entityName: "Setting")
let phoneNumber = try context.executeFetchRequest(request)
if phoneNumber.count > 0{
for item in phoneNumber as! [NSManagedObject]{
let number = item.valueForKey("phoneNumber")
print(number!)
}
}
}catch{
}
This is my solution
let moContext: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = moContext.managedObjectContext
guard let phoneNumber = phoneNumber.text where phoneNumber.characters.count > 0 else {
return// returns if textField is empty.
}
let fetchRequest = NSFetchRequest(entityName: "Setting")
fetchRequest.predicate = NSPredicate(format: "phoneNumber = %#", phoneNumber)
do{
let request = NSFetchRequest(entityName: "Setting")
let phoneObjectArray = try context.executeFetchRequest(request)
guard let settingFetched = phoneObjectArray as? [Setting] where settingFetched.count > 0 else {
// if enters here -> 0 phone numbers were found
if let setting = NSEntityDescription.insertNewObjectForEntityForName("Setting", inManagedObjectContext: context) as? Setting {
setting.phoneNumber = phoneNumber
// call context.save()
}
return // this I forgot
}
let settingObject = settingFetched.first
// fetch results return store phone number.
// update phone number
settingObject.phoneNumber = phoneNumber
// call context.save()
} catch let error as NSError! {
print("error: \(error)")
}
You need to call the "save()" function to persist the information.
I did some changes to the name variables, added some validations and assume some model class name based on your code.
I always recommend to use your NSManagedObject subclass (Setting I assume) instead of just using NSManagedObject and key/value coding.
There could be some minor syntax mistakes on the code because I was using a text editor.
Hope this helps!
For what you want to do, Core Data is overkill.
Use NSUserDefaults instead. So much easier.

Resources