Przemek Bartnik
Przemek Bartnik

Reputation: 37

core data get related entities

I have entities Application and Process, one application can have many processes, but one process can only have one application. I get one specific application entity:

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext
    let appfetchRequest = NSFetchRequest(entityName: "Application")
    //appfetchRequest.returnsObjectsAsFaults = false
    do{
        let results = try managedContext.executeFetchRequest(appfetchRequest)
        applications.addObjectsFromArray(results as! [NSMutableArray])

    }catch let error as NSError{
        print("Jakis blad z applications entity: \(error)")
    }

    let predicate:NSPredicate = NSPredicate(format: "name == %@", appTitle)

    let application:NSArray = applications.filteredArrayUsingPredicate(predicate)

and in this I have relationship (named applicationprocesses). I try to get an array with these entities in many ways, but no one work. Actually, I have:

    let processes = application.valueForKey("applicationprocesses").allObjects.first

    print(processes?.valueForKey("applicationprocesses"))

And this give me:

Optional({(
<NSManagedObject: 0x7f945871b7a0> (entity: Application; id: 0xd000000000080002 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Application/p2> ; data: {
appcolor = "#3F3F3F";
appicon = bed;
applabel = Proces;
applabelplural = Procesy;
applicationprocesses =     (
    "0xd000000000140004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p5>",
    "0xd000000000100004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p4>",
    "0xd000000000180004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p6>",
    "0xd0000000001c0004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p7>",
    "0xd0000000000c0004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p3>"
);
companyid = 392;
id = 1261;
name = "aplikacja 1";
processescount = 5;
})
)})

I need to display these processes in a UITablewView, so I need an array. I will be grateful for any help.

Upvotes: 1

Views: 950

Answers (2)

R Menke
R Menke

Reputation: 8411

The problem you are having is not the result of a bad line of code somewhere. It is actually working as it is supposed to. But you can make it a lot easier to work with NSManagedObject

Any fetch from your database results in [AnyObject]. If you leave it like it is, you are forced to use key-value coding which is a pain and very easy to mess up.

However it is very simple to create Classes from CD Entities and downcast the fetch result. This is an awesome feature of CoreData that unfortunately is not stressed enough.

link to gist

Your related entities might look like this:

enter image description here

Go to Menu -> Editor -> Create....

enter image description here

Select the entities you want to create a subclass for.

New files will show up in your project :

enter image description here


Now you can use code like this :

Insert objects

Notice the .... as? Company this is the downcast. It allows you to access the attributes from the CD Entity like you would access any attributes from a Struct or Class.

func createACompany() {
    // no appDel here. appDel and managedContext are best declared in the class scope. See gist for entire ViewController
    guard let moc = managedContext else { return }

    guard let company = NSEntityDescription.insertNewObjectForEntityForName("Company", inManagedObjectContext: moc) as? Company else {
        return // guard is handy to "abort"
    }
    company.name = "Apple"

    guard let bob = NSEntityDescription.insertNewObjectForEntityForName("Employee", inManagedObjectContext: moc) as? Employee else {
        return
    }
    bob.name = "Bob"
    bob.company = company

    do {
        try moc.save()
    } catch {
        print("core data save error : \(error)")
    }

    moc.refreshAllObjects()

}

Fetch objects

func fetchCompanies() -> [Company] {

    guard let moc = managedContext else { return [] }
    let request = NSFetchRequest(entityName: "Company")
    request.returnsObjectsAsFaults = true

    do {
        let results = try moc.executeFetchRequest(request)

        guard let companies = results as? [Company] else {
            return []
        }

        return companies

    }catch let error as NSError{
        print("core data fetch error: \(error)")
        return []
    }

}

Get related objects

Look closely at the guard statement.

  • let employeeSet = company.employees -> unwrap of optional NSSet
  • let employees = employeeSet.allObjects -> get all objects in the NSSet
  • as? [Employee] -> downcast the result of allObjects to an Array of Employee

func getEmployees(forCompany company : Company) -> [Employee] {

    guard let employeeSet = company.employees, let employees = employeeSet.allObjects as? [Employee] else {
        return []
    }

    return employees

}

Side note:

If you change your mind about the naming of the class and you change it everywhere. Don't forget the update it here too :

The class field has to be updated.

enter image description here

Similar to the InterfaceBuilder. If you change the class name it will not find it anymore.

Upvotes: 2

Chinh Ngo
Chinh Ngo

Reputation: 33

I believe that you want to get all the managed objects (process) relate to the application object you already got. We usually use the "entity" word for same things as table in database.

I'm sorry I didn't have swift version for this line of code. I'm not sure about my swift skill

NSArray *processes = [[application fristObject] objectIDsForRelationshipNamed:@"applicationprocesses"]

Then use API to convert objectID to ManagedObject

  • (__kindof NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;

The only problem is this API, (NSArray *)objectIDsForRelationshipNamed:(NSString *)key , only supported from version 8.3

Upvotes: 0

Related Questions