How fetch relationship from CoreData in swift? - swift

I think this is simple but i can't find answer for me. I have two tables. Contacts and messages. Like this:
And my relationships are in contacts
And in Messages
enter image description here
I need take SQL: SELECT contacts.nickName, messages.id, messages.message FROM messages JOIN contacts.ccNumber = messages.senderCcNumber
My code for now getting a all data from Messages but i don't know how to join table Contacts to this fetch.
let appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context: NSManagedObjectContext = appDel.managedObjectContext
let request: NSFetchRequest = NSFetchRequest(entityName: "Messages")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "senderCcNumber = %#", argumentArray: ["\(senderID)"] )
request.sortDescriptors = [NSSortDescriptor(key: "added", ascending: true)]
do { resultsMessagesList = try context.executeFetchRequest(request) } catch {}
print(resultsMessagesList)
return resultsMessagesList
Can someone give me a hint ?

CoreData is not a database. You don't need to join any tables (there are no tables).
You shouldn't be storing any foreign keys either.
Once you have a message you can get the contacts array by using message.contacts. You don't need to execute any fetch requests to do this. (Other than to get the message in the first place).
Also, your entities should have singular names (Contact not Contacts).
If your messages have a sender and a receiver then create two relationships one called sender and the other called receiver and connect them to the Contact entity.
I'd recommend investing in a CoreData basics book. Or there are some very good tutorials online. You would be saving yourself time in learning to use CoreData properly.

Related

Swift CoreData: accessing relationship is slower than just fetching by predicate - is it designed that way?

In my app I have 100 libraries that contain 5000 books each.
If I want to print 10 libraries and their 10 most recent additions, I can either fetch them all by accessing the relationship, then .suffix the returned NSSet and run a sort OR I can find the libraries by leaving a libraryID property that I can later use in an NSPredicate such as the following:
let fetchRequest = ... "Library"
let sort = NSSortDescriptor(key: "some key for ordering", ascending: false)
fetchRequest.sortDescriptors = [sort]
fetchRequest.fetchLimit = 10
let libraries = try context.fetch(fetchRequest) as? [Library]
for library in libraries {
let fetchRequest = "Book"
fetchRequest.fetchLimit = 10
let predicate = NSPredicate(format: "libraryID == %#", library.id ?? "")
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "added date", ascending: false)]
...
}
What I do not understand is why the second option uses 15% of the CPU, whereas accessing the relationship directly is about 10 times slower.
My understanding of databases was that we have relationships in place to prevent doing exactly these kinds of things, somewhat hardcoding the ID of a parent property into a child property because now I am questioning what relationships are even good for.
There is one thing where I could see a relationship coming along useful, namely if we were able to perform a .fetch right on the Library object or it's books relationship - is that possible? Because then we wouldn't have to scan the whole table each time but instead only search within the entries of the relationship.
Accessing via the relationship, then sorting and discarding 4950 / 5000 items means that all of that processing has to be done in memory. Using fetch requests means that you can get the database to do the work.
If you have a relationship between the library and its books, you can use that in a predicate. In your code above, that would be something like:
let predicate = NSPredicate(format: "library == %#", library)
That will likely be faster than storing the ID, unless you have an index added on library ID.

Filter to NSFetchRequest

hi i'm not really understanding how the fetch filter works can anyone help me please? So i currently have this as my fetchall function which displays all of my items within my entity
im having trouble of filtering only one attribute which is a boolean. I want it to only display attributes that are true.
thankyou!
func fetchAllItems(){
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "AllItems")
do{
let result = try managedObjectContext.fetch(request)
beastList = result as! [AllItems]
} catch { print("\(error)")
}
}
Code:
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "AllItems")
request.predicate = NSPredicate(format: "something = %#", argumentArray: [true])
Note: Replace something with your boolean field name
Better way to create request
let request : NSFetchRequest<AllItems> = AllItems.fetchRequest()
Naming convention:
It is better to name your entity in singular form, so that each row in your entity could be in singular form.
AllItems seems very generic, if you are storing cars, the entity name could be Car. The variable that stores the result of the fetch request could be cars.
Reference:
https://developer.apple.com/documentation/foundation/nspredicate
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html

Fetching a one to many relationship using Core Data

iam a swift beginner, i wanna code a little app for me and i have a problem with it. My app has three entities (Templates, Records and Positions), here you can see:
Datamodel
At one part of the app i can add new Records and for that Record i add some Positions (xpos and ypos).
At a part I have a tableview were i list my Records. Now i wanna click one Record in the table and i want to get all Position-Attributes linked with the particular selected Record.
With that code i can get all xpos-Positions but how can i get a single xpos? :)
guard let moc = self.managedContext else {
return
}
let fetchRequest: NSFetchRequest<Records> = Records.fetchRequest()
do {
let searchResults = try moc.fetch(fetchRequest)
let xpos = searchResults[0].positions?.mutableArrayValue(forKey: "xpos")
print(xpos)
} catch {
print("Error with request: \(error)")
}
You want to look into using NSPredicate. NSPredicate basically lets you define the conditions which the record needs to meet to be included in the results. Think of it as a filter if you will.
fetchRequest.predicate = NSPredicate(format: "uniqueID = %#", arugments:...)

swift request coredata and delete

i would like to request all my core data where the "mhd" field >= the date of today. this code works fine:
func DatenAbrufen() {
let calendar = NSCalendar.currentCalendar()
let AktuellesDatum = calendar.startOfDayForDate(NSDate())
let fetchRequest = NSFetchRequest(entityName: "LM_ITEMS")
fetchRequest.predicate = NSPredicate(format: "mhd >= %#", AktuellesDatum)
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [LM_ITEMS] {
lebensmittel = fetchResults
}
}
how can i delete in this query all other data, where "mhd" is not >= date of today?
If you need to support iOS 8.x, or OS X Yosemite, or older, you'll need to fetch each object and then delete it. Write another predicate that is the opposite of the one you have. Execute that fetch request. Then iterate over the found objects and send each one a deleteObject. Save your managed object context. This can take quite a while, if you're deleting lots of objects.
For iOS 9 and El Capitan, you can use NSBatchDeleteRequest, described in WWDC 2015 session 220. For large numbers of deleted objects, NSBatchDeleteRequest is much faster. You're not loading each object into memory just to delete it. You also bypass some validation rules, and must refresh your MOC for it to see changes–which might be undesired consequences, depending on your usage.

How to sort the results of an NSFetchedResultsController using the order of an NSOrderedSet

NSOrderedSets save the order of the objects in the table. If you access an NSManagedObject subclass instance with a property that is an NSOrderedSet, then they will be in order.
However, there is seemingly no way to access that order using an NSSortDescriptor when creating an NSFetchRequest.
It appears from the raw SQLite DB, that order is stored in fields named Z_FOK_<relationship name>. The data is available, but it doesn't appear to be visible through the core data APIs.
Does anyone know a way to write an NSSortDescriptor that will work with a SQLite DB to return the results in the order specified by the NSOrderedSet?
Update
Related Question: NSFetchedResultsController and NSOrderedSet relationships
I don't think that is possible. The "ordering" is associated with the to-many relationship from one entity A to another entity B, it is not a property of the target entity B.
But a sort descriptor for a Core Data fetch request can only use (persistent) properties of the entity.
I've tried this in swift just now and it seemed to work for me.
var sectionsExcludingEmpty: [SurveyAnswerSection] {
let fetchRequest: NSFetchRequest<SurveyAnswerSection> = NSFetchRequest.init(entityName: "SurveyAnswerSection")
fetchRequest.predicate = NSPredicate.init(format: "surveyAnswer == %# AND hidden == FALSE", self)
fetchRequest.sortDescriptors = [ NSSortDescriptor(key: "surveyAnswer", ascending: true) ]
if let moc = self.managedObjectContext {
do {
let results = try moc.fetch(fetchRequest)
return results
} catch {
fatalError("Could not get sectionsExcludingEmpty: \(error)")
}
} else {
fatalError("Unable to get own managed object context")
}
}
When I missed off the line fetchRequest.sortDescriptors = [ NSSortDescriptor(key: "surveyAnswer", ascending: true) ] it ordered seemingly randomly, but with the line added it sorted as expected.
In my case SurveyAnswerSection has a one to ordered-many relationship with SurveyAnswer.