This post originated from an RSS feed registered with Agile Buzz
by Keith Ray.
Original Post: Using Cocoa's Reflection APIs for Reading/Writing an SQL Database
Feed Title: MemoRanda
Feed URL: http://homepage.mac.com/1/homepage404ErrorPage.html
Feed Description: Keith Ray's notes to be remembered on agile software development, project management, oo programming, and other topics.
CoreData is probably doing something like this already. If you don't like CoreData's use of sqlite3/XML or being limited to the Tiger version of MacOS X, you can probably use these APIs to implement your own object-to-database mapping. If you want to work with a database schema that doesn't map simply to your classes, look elsewhere. Also: I'm just getting to know SQL-based databases, so I may be mis-using SQL/DB terminology or concepts.
Writing to the database:
1. Call the method "className" to get the object's class-name and map that to a database table. You probably also want to map object addresses to a unique id in that database table.
2. Calls these methods to find keys of the object and map those to column-names (and possibly foreign keys to other tables): "attributeKeys", "toOneRelationshipKeys", "toManyRelationshipKeys"
3. Get values for keys by calling "valueForKey:" or "dictionaryWithValuesForKeys:". There's also "mutableArrayValueForKey:" for dealing with to-many relationships.
4. Assemble SQL from the classname/tablename, key-names/column-names, and values gotten above, and use that to write to the database. You'll probably need to write multiple rows to multiple tables to persist a complex aggregate object, thus you need to use techniques common to object-serialization to detect cycles and avoid writing an object to the db more than once. One of the PLoP books had a good discussion of serialization.
Reading from the database is pretty much the reverse of the above, but getting to the class from a classname/tablename requires calling NSBundle's "classNamed:" method or some other method or function I haven't found in my quick search using AppKiDo while writing this. Once you have the values and key-names, set them with the method "setValue:forKey:" or "setValuesForKeysWithDictionary:".
Cocoa has bunches of interesting methods like "classForArchiver" and "replacementObjectForArchiver:" that are probably used behind the scenes for implementations of Distributed Objects, reading/writing NIB files (in various NIB file formats, which recently included XML, I believe), and more recently, Core Data. Maybe someday I'll get more familiar with these. Oh, I haven't actually done this (yet), so don't ask me for help if you get stuck. :-)