The macosxhints Forums

The macosxhints Forums (http://hintsforums.macworld.com/index.php)
-   OS X Developer (http://hintsforums.macworld.com/forumdisplay.php?f=27)
-   -   Core Data key/binding question (http://hintsforums.macworld.com/showthread.php?t=96152)

jmunsonii 11-24-2008 01:35 PM

Core Data key/binding question
 
Namaste!

OK, I'm weeding through my first Macplication. I have an existing application that I'm porting over to the Mac. Quite the learning curve. The original was written in VB .NET & WPF w/ Visual C#.

In my application I have many master/detail views. One screen has a master with multiple detail views that are aspects of the master. I also have some views that are as a result of a relationship between two entities (just a key table essentially).

My question is: how do I bind the child views to the master?

I've read through a great deal of the documentation, but it doesn't shed good light on the subject.

For simplicity's sake, in a model, there are two entities: Family and Person. A person belongs to a family, and a family has many persons. As the model doesn't actually define a key (keeping to strict logical), how does this get bound in a master/detail relationship?

Another example for the second issue: Job and Employee. There are many Jobs to which an Employee can belong, and likewise many Employees (possible) for a given job. How does one set the bindings here too?

Then, as a follow-on, how does one bind the selectedValue of a popup? There is no key - does it get bound to the relationship?

Looking forward to an answer. :D

Thanks well in advance!

Peace, Love, and Light,

/s/ Jon C. Munson II

bramley 11-25-2008 09:00 AM

Your post is too confusing to understand clearly what your problems are.

I can see that you are trying to port an application to run under Cocoa. But it's hard to see deeper than this.

You seem to be blending two different concepts into one. Core Data and bindings are separate concepts and are often used independently of each other.

Core Data is concerned solely with data modelling - it has no connection with the GUI. Relationships exist between data model entities, which can have properties. Bindings has no meaning in connection with Core Data.

Bindings is a technology that links elements of the GUI and controller objects (subclasses of NSController) to reduce the amount of code written to keep the data model objects synchronised with their onscreen representations.

I suspect that your starting point here should be from a book on Cocoa rather than posts on an forum. Several books have been recommended on this forum in a number of other threads.

hayne 11-25-2008 09:33 AM

I second the recommendation for a book on Cocoa.
It is a waste of your time to try to learn it without a good book - e.g. that by Hillegass.

And for your first (second, ++) Cocoa app, you should create small, simple apps - not try to port an existing app.
I.e. you need to take the time to learn Cocoa before trying to use it for a real app.

jmunsonii 11-25-2008 09:43 AM

Points of confusion
 
Namaste!

Thank you for your reply.

Actually, you are both right and wrong on a few issues.

Core Data Modeling is indeed designed to model entities for either use or persistent storage.

In that respect, when you construct your user interface, at some point you have to connect it to the model.

Therein lies my quandry.

In Cocoa, the model is rather strictly relegated to a more logical definition (i.e., no keys, etc.). Whereas in a physical database model the keys, and so on, are created in each of the entities. Thus, when connecting to the model in the user interface, my normal connections are "missing."

I stand by my simplistic example to illustrate my point.

Example entities: Departments, Employees. Departments can have Employees, and Employees can have departments.

In the Cocoa model, this is expressed via two entities with "to-many" [why Apple had to depart from a "many-to-many" expression is beyond me] relationships to each other (inverses).

Now several user interface descriptions can be used to implement that model based upon the intended use of the application (business rules of application operation).

Let's break this down into two basic problems:

1. In the case of Employee having a Department (a "future" release would be for departments), the user interface would have some fields for the employee data and a popup to select the department. As there is no key defined in the Employee entity (the relationship results in a physical intermediary key table), to what does on bind the selectedValue attribute of the popup?

2. In the case of Department having many Employees, the user interface requires fields for basic Department data (Master side), and a table for the Employees (Child side, which is a result of the relationship). How/to what does the table get bound?

In my thorough (and yes, I mean thorough) searching of what documentation/examples I can find on Core Data, Apple doesn't explicity give any example that is close to this and also doesn't provide something that I can trace back to their example models, etc. Also, I couldn't find a third-party example that shows this sort of thing.

So, yes, I have read through all kinds of materials. To belabour the point further, I have read Hillegass' book, the Apple Core Data dox, and a few examples (some of which I had used to answer other questions).

Now, does that shed better light on my situation?

Thanks!

Peace, Love, and Light,

/s/ Jon C. Munson II

Mikey-San 11-25-2008 12:31 PM

#include "bramleys_post.h"
#include "haynes_post.h"

jmunsonii 11-25-2008 01:05 PM

I mean this in a nice way: Mikey-San, those types of replies aren't much help at all.

hayne 11-25-2008 01:16 PM

Note that Mikey-San's post predated (in visibility) your second post (post #4 in this thread) since your second post had not yet passed moderation at the time Mikey-San posted that.

jmunsonii 11-25-2008 01:17 PM

Yes, I know. Hence the predicated "nice way."

Truly, I am looking for help and am not trying to be mean.

hayne 11-25-2008 01:21 PM

Mickey-San was merely adding his support to the ideas expressed by myself and bramley.
This was in fact intended to be helpful, given the info you supplied (or didn't supply) in your first post.

Anyway, let's stop with the meta-discussion and just post about the problem.

jmunsonii 11-25-2008 08:24 PM

A diagram from Apple dox that may help...
 
Namaste!

I think this may begin to explain some things, but I do have follow-on questions:

http://developer.apple.com/documenta...s_bindings.gif

Here are the questions I have:

1. What is "selectedWeapon?" Is it a class-created property, or is it a "magic" (one that Cocoa creates) property? I can't tell which from the diagram.

2. What is selection.weapons? Is it a class-created property (i.e., the programmer created that), or is it something that Cocoa presents as a plural form of the entity Weapon?

While the physical connection part isn't hard or difficult to grasp, the "what" of the connection is, at least to me. I need something a little bit more "real" than that...

Hope this further explanation helps...

Peace, Love, and Light,

/s/ Jon C. Munson II

hayne 11-26-2008 01:31 AM

I'd strongly recommend not trying to understand bindings from that diagram and instead:
- go through (implementing, step by step - not just reading) one or two bindings tutorials
- read through what is on the CocoaDev page on bindings: http://www.cocoadev.com/index.pl?CocoaBindings
- look at all of the examples provided by Apple under /Developer/Examples/AppKit
- look at all of the bindings examples on mmalc's page: http://homepage.mac.com/mmalc/CocoaE...ntrollers.html

Note that you need to understand key-value coding before you can understand binding.

jmunsonii 11-26-2008 03:58 PM

One question answered...
 
Namaste!

OK, after much browsing, I saw one person make the suggestion of dropping a Core Data Entity into a NIB and examining that.

So, I did.

While it still doesn't answer the Parent/Children form, it did answer one question (and some others as I go along): popup/combo bound using the relationship. The answer is: bind the popup's selectedObject to the "primary" (the entity's whose data you are manipulating) selection.<relationshipName> in the Selected Object bindings section. This is the "key" field/attribute in that case. Thus, you might have Person.selection.theDepartment. theDepartment would be the relationship you have defined in the Person entity. For that to work, one needs a managed object context. I specified Application.delegate.managedObjectContext (also from another's post).

Naturally, this leads me to question IF I can "continue down the tree." In other words, can I then use, in the case of a child form, Parent.selection.relChild.childName, Parent.selection.relChild.childDOB, etc., as bindings for a table view...

In a way that makes sense, but I have no idea. I'll give it a try anyway... 'Course, then comes the natural extension of that, which is, how to bind a popup in a child table view...

One doesn't know until one tries.

Peace, Love, and Light,

/s/ Jon C. Munson II

jmunsonii 11-26-2008 05:53 PM

Namaste!

I took a look through the sample applications to see what I could find that would tell me how to construct the appropriate UI to express/facilitate the entity model.

I found EventManager in the sample apps.

It demonstrates parent/child relationships & popup bindings, etc.

A gold mine! [:)]

Now, if "you all" knew that was where I needed to look, I wish you would have told me, as that took me a great deal of time to find. But, that's OK, I found it nonetheless (with your urging).

Anyway, after studying the NIB, I've come to these conclusions:

1. For each entity used in the Parent/Child "form," one needs a controller array (i.e., Family, Parents, Children, each with their own array).
2. For each controller array, the bindings are done as normal to each entity, EXCEPT the contentSet is bound to the appropriate parent entity and the modelKeyPath is the name of the relationship.

And that appears to be that...

Seems simple enough.

Is that correct?

Peace, Love, and Light,

/s/ Jon C. Munson II

jmunsonii 11-26-2008 08:04 PM

Namaste!

I went over mmalc's controller samples and inspected the Departments/Employees sample. I am also reading through the cocoa bindings (which I've been through a couple of times previous).

OK, the EventManager sample didn't answer one question: how to bind to a many-to-many relationship where there is no child table between them. For instance, Roles and Persons. Each Person may have one or more Roles, and each Role may belong to one or more people. In the object model this is simply a to-many relationship with the same inverse between the entities.

What is the correct key value coding for this situation?

Person.selection.roles doesn't work (where roles is name of the relationship).

This situation isn't in the EventManager sample and doesn't fit the conclusions I was able to draw from that sample. Nor is it a "Master/Detail." So, none of the samples I looked at demonstrated it either.

If there is a doc page I could examine, let me know what it is.

Thanks!

Peace, Love, and Light,

/s/ Jon C. Munson II

Treth 11-27-2008 02:56 AM

Ok, I think I can say what the rest of them know the way that you want to hear it, because I'm coming from where you are and I probably would have offended many a proud Cocoa developer by asking here instead of reading class documentation. I still don't fully understand how to use Core Data, even though I'm pretty sure I conceptually understand how it works, so maybe you can help me if I haven't got it by the time you get your program done. :-)

Basically, you can almost think of Core Data like a protocol. Programmers started to notice that all the data in a program was represented twice. An value stored on disk, for example, and an internal variable of a UI control represent the same 'idea' in a program, and would perhaps ideally be only a single variable. Because that is very difficult to do, programmers would have to make several copies of a variable and write code to keep them behaving as one value. This puts the burdens of design and implementation correctness on the programmer, which means that you have to debug not only the code that gets information from the user and the code that saves to disk, but also the code that connects them.

You can imagine, then, that Core Data is about making this information apparent to the runtime. In C++, for example, the only part of the program that knows that this integer over here and that integer over there are one value is the glue code you wrote to hold them together. But using Core Data, we can tell the runtime that this identifier on this object and that identifier on the other are one single idea, and we are guaranteed correct behavior by the runtime.

What this means relative to your data model can be compared to a database. An entity without any keys is like a row without any columns. Certainly, one could make several rows which contain no columns and they would be distinct from one another in some implementation sense (different addresses on disk, or differently id'd objects), but in the logical flow of any program such a construct is meaningless.

Controller keys are member variables of controller objects. You can look those up just like regular classes, by looking at the class name for the object in question (NSArrayController for 'Array Controller', etc). Model key paths are variables that are added by Core Data, that are not formally a part of the class; they 'piggyback' on managed objects. The easiest logical way to make this distinction is to ask whether what you're trying to reach is a part of your data model ('name') or a part of the context of your data itself ('selection').

If the Core Data model is then nothing but the data, then we need to manipulate it. More than just giving you access to entities inside Interface Builder, attaching controllers actually pins code to specific points in the data model and can even represent your own custom controller subclasses.

I believe Apple's departure from normal nomenclature (to-many, to-one) is designed to reduce confusion, since many-to-anything relationships seem unsupported. I think if you need to represent a many-to-many relationship, then it's thought your best bet is to use SQLite.

I'm not an expert OS X programmer, so I may be mistaken and I would be very grateful for any corrections should that be the case. I try to be verbose in these kinds of posts to make it less likely that I'm misunderstood, and I hope I've not been too long-winded. I hope your software project goes well, and congratulations on making the jump!

jmunsonii 11-27-2008 09:26 AM

Namaste!

Thanks Treth for your reply.

I come from 8+ years of working with RDBMSs (like Jet, MSSQL, etc.), so CoreData isn't really that foreign to me. Neither is the concept of "bindings" - MS uses this in most of it's UI construction (one binds a control's event to a function, which isn't that dissimilar
to the Cocoa bindings). The NS way of doing things is just a little different, but, to me, it really isn't all that magical. What IS cryptic is the proper paths for the key value, but that's coming as I work with it.

I see CoreData acting as an "engine" for a data structure (entities). It also provides a physical store for persistency. That store is in XML or SQLite. I believe that you can take a SQLite datastore to a next level, but am not sure how one does that. Not really important at this time for my needs.

That being said, from an RDBMS modeling standpoint, CoreData models most closely reflects a Logical View. This view contains the nomenclature/attributes for the entities and their strict relationships. By contrast, the physical view contains the entities, their attributes, and the necessary intermediary entities for managing true many-to-many relationships (essentially these are only key tables).

When a CoreData model is implemented, CoreData creates the necessary "id" for each entity within the system, hiding that value from the programmer (which is fine, but may introduce some "bugs" later on, as opposed to say, a SQL Server that has "you" manage the keys). The programmer then hooks his code/interface to the relationship that deals with that entity set (the selection).

That all works well and good, as long as there is an actual entity that is the receiver of a one-to-many or one-to-one relationship. The issue comes in for a many-to-many - there is no entity between (unless there are attributes that qualify that relationship, but that results in a one-to-many relationship anyway), logically speaking.

Thus, using the normal method of binding the contentSet to Parent.selection.relationship fails when the relationship is a true many-to-many (no key table between).

I'm not finding any samples or documentation that explains how to implement such a relationship. So far, everything I've seen has been a one-to-many.

That's fine, but it would be nice to get some sort of confirmation. And then, does one need to create the key tables (which would only have relationships)? I don't know as I haven't reached that point to experiment (while researching I am working on other parts of my application).

And, when one switches the store to SQLite, does CoreData then create the intermediary tables in the model? The documentation states it creates them in the store.

Think I'll just try that out when I get to that point...

Thanks again!

Peace, Love, and Light,
/s/ Jon C. Munson II

jmunsonii 11-28-2008 12:34 PM

KVC issue
 
Namaste!

After having done many hours of investigating, head-scratching, trial/error, and more searching, I've gotten stuck.

I created a simple scenario to work out how to accomplish a many-to-many situation. I created two entities: Person and Hat. They are defined thus:

Person:
personName: string
relHats: to-many relationship to Hat

Hat:
hatName: string
relPersons: to-many relationship to Person

The relationships are inverses.

I started the NIB by dragging a Core Data Entity for Person, creating a master table automatically (I didn't feel like making all the connections at this point). The resulting box was then dragged onto the window in the NIB. This also created a Person Array Controller object in the NIB that is bound as an Entity to Person.

I then dragged two more array controllers to the NIB. One for Hat (as the source for a popup) and one for the Person_Hat relationship. Hat's bindings are self-explanatory.

Person_Hat has the following bindings:

contentSet:Person.selection.relHats
MOC:AppName_AppDelegate.managedObjectContext

I then dragged a tableview onto the window, and two buttons. The tableview has one column, which is a popup. The tableview column's bindings are:

content: Hat.arrangedObjects
contentValue: Hat.arrangedObjects.hatName
selectedObject: Person_Hat.arrangedObjects.relPersons

One button is for adding a new Person_Hat record, the other for adding Hat records.

Running this application produces a key-value coding compliance error:

2008-11-28 12:21:45.490 TestManyToMany[1550:10b] [<NSManagedObject 0x1ac7e0> valueForUndefinedKey:]: the entity Hat is not key value coding-compliant for the key relHats.

I know the issue is in the tableview column bindings. However, trying different things doesn't address the issue (but does create others).

I compared what I have with the sample application, Event Manager, and what I have appears to correspond with the way that application is set up. The main difference being that EventParticipant (which corresponds with Person.relHats in my sample) is a separate table.

I haven't been able to resolve this problem, which is very key to getting my actual application to work.

Theoretically, from my vantage, this should function.

Anyone care to help out on this one? If this simply can't be done, just tell me so I don't waste any more time on it and I'll go another route.

Thanks!

Peace, Love, and Light,

/s/ Jon C. Munson II

hayne 11-28-2008 01:10 PM

Have you read: http://developer.apple.com/documenta...eshooting.html
?

jmunsonii 11-28-2008 01:36 PM

Yes, I did.

I did set the debugging level.

Running the app results in these messages:

2008-11-28 13:29:53.091 TestManyToMany[1726:10b] Cocoa Bindings: Error setting value {(
<NSManagedObject: 0x13d0e0> (entity: Person; id: 0x1580b0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Person/p103> ; data: {
personName = "New Person";
relHats = (
0x15c0d0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Hat/p106>
);
})
)} of object <NSPopUpButtonCell: 0x12cf90> through binding selectedObject
2008-11-28 13:29:59.190 TestManyToMany[1726:10b] Cocoa Bindings: Error setting value {(
<NSManagedObject: 0x13d0e0> (entity: Person; id: 0x1580b0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Person/p103> ; data: {
personName = "New Person";
relHats = (
0x15c0d0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Hat/p106>
);
})
)} of object <NSPopUpButtonCell: 0x12cf90> through binding selectedObject
2008-11-28 13:30:01.161 TestManyToMany[1726:10b] Unacceptable type of value for to-many relationship: property = "relPersons"; desired type = NSSet; given type = NSManagedObject; value = <NSManagedObject: 0x194e60> (entity: Hat; id: 0x15c0d0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Hat/p106> ; data: {
hatName = "New Hat";
relPersons = (
0x1580b0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Person/p103>
);
}).
2008-11-28 13:30:01.173 TestManyToMany[1726:10b] Cocoa Bindings: Error setting value {(
<NSManagedObject: 0x13d0e0> (entity: Person; id: 0x1580b0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Person/p103> ; data: {
personName = "New Person";
relHats = (
0x15c0d0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Hat/p106>
);
})
)} of object <NSPopUpButtonCell: 0x12cf90> through binding selectedObject
2008-11-28 13:30:05.993 TestManyToMany[1726:10b] Cocoa Bindings: Error setting value {(
<NSManagedObject: 0x13d0e0> (entity: Person; id: 0x1580b0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Person/p103> ; data: {
personName = "New Person";
relHats = (
0x15c0d0 <x-coredata://873AC054-69EB-429A-8166-75596C2B19A6/Hat/p106>
);
})
)} of object <NSPopUpButtonCell: 0x12cf90> through binding selectedObject

I am not sure of what to make of it. I could theorize, but that's not going to get me anywhere.

jmunsonii 11-28-2008 02:54 PM

Round 2 of previous...
 
OK, I took another look at things. Still have a problem that I'm stuck on.

I double-checked my bindings vs. the EventManager sample's bindings and noted I did actually have some differences (probably from further experimentation). So I reverted them. The bindings in my test app are now:

Person_Hat
contentArrayForMultipleSelection: Person.selection.@unionOfSets.relHats
contentSet: Person.selection.relHats

Running the app with debugger messages turned on results in the following message when attempting to add a new hat to the Person_Hat relationship:

2008-11-28 14:47:32.075 TestManyToMany[1944:10b] Unacceptable type of value in to-many relationship: property = "relHats"; problem = {(
<NSManagedObject: 0x12c2b0> (entity: Person; id: 0x10e380 <x-coredata:///Person/t4A1FE643-8569-474D-B50E-CB290107D4D22> ; data: {
personName = "New Person";
relHats = (
);
})
)}; desired type = NSManagedObject_Hat_; given type = NSCFSet; value = <NSManagedObject: 0x12c2b0> (entity: Person; id: 0x10e380 <x-coredata:///Person/t4A1FE643-8569-474D-B50E-CB290107D4D22> ; data: {
personName = "New Person";
relHats = (
);
}).

Don't know what to do with that. Again, the only difference (now) between my app and the EventManager app is the EventParticipant is a seperate entity as opposed to a relationship.

Looking forward to your help.

Thanks!

Peace, Love, and Light,

/s/ Jon C. Munson II

jmunsonii 11-29-2008 11:53 AM

I'm still stuck on this. I've tried to flatten out the relationship, same error. I recreated the test app using the Document architecture, same issue. There is no "custom" code in my app, nor is there any in the EventManager that would cause things to be different.

I simply cannot see the "the answer." (providing there is an answer)

hayne 11-29-2008 03:49 PM

You might get more response posting about this on one of the developer mailing lists - start at lists.apple.com

jmunsonii 11-29-2008 04:24 PM

Thanks hayne! I'll give that a shot.

jmunsonii 12-01-2008 10:01 AM

Again, thanks hayne - I wasn't aware of the "lists." On the MS Windows side, all is done by forum and not by email lists. A bit easier in my mind, however, it gets the job done.

At any rate, I did get something figured out. Creating a "key" table works (when the bindings are set correctly).

In other words, e'en though Person & Hat have a many-to-many relationship, it APPEARS that CoreData can't directly support that. The developer must put a key table between to hold the relationships. Thus, an entity called Person_Hat needs to exist that has to-one relationships with Person & Hat, which are the inverse of the to-many relationships from Person & Hat. I got that functional this morning.

Though Apple dox clearly show many-to-many relationships as a possibility, a strict many-to-many isn't necessarily supported.

I'm still waiting to hear back from the list as to any particular reason why that doesn't/cant work.

Thanks again for any assistance.

Peace, Love, and Light

/s/ Jon C. Munson II


All times are GMT -5. The time now is 05:57 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.