Coredata nested relationships retrieving data - ios

I have the following entities:
Orders <-->> OrderLines <<--> Products
An Order entity has an 'orderNo' attribute that has a one to many relationship with an 'orderNo' attribute in OrderLines.
The OrderLines entity has can have a many to one relationship with the Products entity.
I want to pass a customer code and retrieve all products that we currently have in the Products entity that they have ordered before.
I have tried the following predicate search to no prevail:
let pred : NSPredicate = NSPredicate(format: "orderlines.order.customer = %#", customer)
I've also tried
let pred : NSPredicate = NSPredicate(format: "ANY orderlines.order.customer = %#", customer)
I'm usually faced with an error of:
Can not map from a to-many to a to-one relationship
Any advice?
UPDATE
The code retrieving the data is:
static func repeatsList(customer: String) -> NSArray{
let ordersRequest : NSFetchRequest<Products> = Products.fetchRequest()
let pred : NSPredicate = NSPredicate(format: "ANY SELF.line.order.invoicecustomer == %#", customer)
ordersRequest.predicate=pred
do{
let repeatsArray = try GlobalHelpers.getContext().fetch(ordersRequest)
return repeatsArray as NSArray
}catch let error as NSError {
let empty : NSArray = [error]
return empty
}
}

Related

CoreData fetching all one-to-many relationship

I have two classes, Session and Course, with a one-to-many relationship between a session and courses. I'm trying to fetch all of a session's courses using an NSPredicate. The predicates I have tried throw errors.
let fetchRequest: NSFetchRequest<Course> = Course.fetchRequest()
guard let startDate = session.startDate else {
fatalError("Attempting to fetch courses for session without a start date")
}
let sessionPredicate = NSPredicate(format: "ALL %K == %#",
#keyPath(Course.session.startDate),
"\(startDate)")
fetchRequest.predicate = sessionPredicate
If you want to find all courses whose session has a given start date it's easier:
let sessionPredicate = NSPredicate(format: "session.startDate == %#", startDate)
NSManagedObject provides full KVC support

coredata fetch with predicate for object relation using swift

I'm trying to perform a fetch for an entity in coreData. This entity has a one to one relation with another entity. I want to only get the items in the first entity that have a relation to a particular item in the second entity. I'm trying this predicate which I know is incorrect:
let fetchRequest: NSFetchRequest<ItemA> = NSFetchRequest(entityName: "ItemA")
fetchRequest.predicate = NSPredicate(format: "itemA.itemB.itemBId == %d", Int(itemB.itemBId))
Currently you are using itemA.itemB.itemBId , here you are using a new entity of itemA , where as you dont need to give its name, since this predicate will be applied on itemA entity, so either you can use only itemB.itemBId inside predicate or you can use SELF.itemB.itemBId (I am not sure about SELF or self, obviously you can look it up).
So I think you can get the items of type itemA whose relation itemB has an id of itemBId like this:
let fetchRequest: NSFetchRequest<ItemA> = NSFetchRequest(entityName: "ItemA")
fetchRequest.predicate = NSPredicate(format: "itemB.itemBId == %d", Int(itemB.itemBId))

Do this to core data: "Select * WHERE "attribute" == "Some string" "

I did manage to do this by making a function with a loop that checks the attribute to a string. But i'm looking for a better way to do this.
In sql I do this:
Select * WHERE "attribute" == "string"
Is there a method to do this in swift?
My function looks like this:
func tableData()
{
let objects = retrieveValues("JobTime") //Retrieve a NSMutableArray
if !objects.isEmpty
{
for var index = 0; index < objects.count; ++index
{
if objects[index].valueForKey("jobTitle") as? String == transferTitle
{
print("Job title matched: \(index)")
}
else
{
print("Nothing here!")
}
}
}
}
In order to perform fetch request in CoreData you have to initialise NSFetchRequest class. In order to specify in what kind of entities you are interested you create NSPredicate class. It gives you ability to specify pretty advanced queries. In most cases the simplest way to create NSPredicate is by using format string - details about the syntax can be found Apple's Predicate Format String Syntax document.
You can find example of how you can perform fetch request in CoreData (and Swift) below.
let managedObjectContext: NSManagedObjectContext
let predicate = NSPredicate(format: "jobTitle == %#", "Programmer")
let fetchRequest = NSFetchRequest.init(entityName: "People")
fetchRequest.predicate = predicate
//fetchRequest.sortDescriptors = [] //optionally you can specify the order in which entities should ordered after fetch finishes
let results = managedObjectContext.executeFetchRequest(fetchRequest)
You can pass the query to CoreData and only retrieve what you want. The NSManagedObjectContext class has a executeFetchRequest method that you call to retrieve data from the database. You pass NSFetchRequest object to it. That object contains a NSPredicate, which defines your query.

NSPredicate to use with Transformable property

I have array of strings which I save in Core Data as Transformable. From json I am gettings needed strings like this:
if let mealTimes = dictionary["mealTimes"] as? [String]{
self.mealTimes = mealTimes
}
Now I would like to filter fetch results by strings in mealTime property. I have tried this way:
let predicate = NSPredicate(format: "mealTimes LIKE[cd] '*%#*'", "breakfast")
var breakfastContents = StaticContent.fetchStaticContentsWithPredicate(predicate, inManagedObjectContext: self.coreDataStack.context)
if (breakfastContents.count > 0) {
breakfast = breakfastContents.first!
}
The problem is that result array is empty but I know I have breakfast string in some content. So how can I fix it? I was reading something about saving transformable as NSData so it would need some great trick. I was trying to use LIKE (with and without *) command and CONTAINS.
Extension for StaticContent:
class func fetchStaticContentsWithPredicate(predicate: NSPredicate, inManagedObjectContext managedObjectContext: NSManagedObjectContext) -> [StaticContent] {
// Define fetch request/predicate
var fetchRequest = NSFetchRequest(entityName: "StaticContent")
// Assign fetch request properties
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
// Handle results
let fetchedResults = managedObjectContext.executeFetchRequest(fetchRequest, error: nil) as! [StaticContent]
return fetchedResults
}
You should refactor your data model to get rid of the "array of strings". This is not a very sound way to store this type of values.
Instead, consider a relationship with a new entity that captures those strings. Alternatively, device a scheme where you store a string and have a unique character that separates the records (e.g ; or something similar). Then any simple string predicate would work, like this:
NSPredicate(format: "mealtimes contains[cd] %#", "breakfast")

Issue with fetching sorted records (CoreData)

I'm having
two entities record and group.
one to many relationship, so each group can have multiple record.
in group -> (relationship:arrRecord, Destination:record, Inverse:recordGroup)
in record -> (relationship:recordGroup, Destination:group, Inverse:arrRecord)
I am able to fetch group and respective records. But I am not able to fetch group and respective records sorted by record field 'name'.
code:
let fetch: NSFetchRequest = NSFetchRequest(entityName: "group")
if let fetchGroups = APP_DELEGATE.managedObjectContext!.executeFetchRequest(fetch, error: nil) as? [group]
{
for group in fetchGroups
{
let sortDesc = NSSortDescriptor(key: "name", ascending: true)
let arrSorted = group.arrRecord.sortedArrayUsingDescriptors([sortDesc])
print("arrSorted === \(arrSorted)") // sorted by name
group.arrRecord = NSSet(array: arrSorted)
print("NSSet(array: group.arrRecord) === \(group.arrRecord)") //not sorted by name
}
}
arrSorted is being sorted, but when converted back to NSSet, order resets :(
The 'To Many' relationship results in an NSSet (or NSOrderedSet, if you have checked 'ordered'), which is not a sorted collection.
You can use - (NSArray *)sortedArrayUsingDescriptors:(NSArray *)sortDescriptors to get a sorted NSArray.

Resources