Database Object Persistence
BlitzMax Forums/Brucey's Modules/Database Object Persistence
| ||
Currently I'm just messing around with some ideas, but I thought it would be fun to have the ability to take a BlitzMax Object, and almost-transparently fetch/save it to a database. Using Reflection as a starting point, I came up with this : Type Person Extends MDO {table="PERSON"} Field id:Int {generator="native" column="id"} Field forename:String {column="forename"} Field surname:String {column="surname"} End Type "column" tag is optional if field and column are the same name. "generator" I just lifted from Hibernate, and doesn't mean anything yet. Rather than processing everything "on-the-fly", we pre-process the "MDO" types, to generate some helper code. It's this code which will do all the hard work for us. So, imagine our application. We connect to a database, open a session, and retrieve some data from it : Local db:TDBConnection = LoadDatabase("SQLITE", "maxtest.db") Local session:DBSession = DBSession.Create(db) Local p:Person = Person(session.get(New Person, TInt(2))) This will fetch and populate a Person object, for the id "2". Here's the generated SQL : SELECT id, forename, surname FROM PERSON WHERE id = ? I've yet to work out a caching mechanism, which would allow it to reuse the prepared statement. But for a first step, it's working well, and as you can see, requires far less code to be written than it would if you were to do it by hand. Anyway, at some point, it might fit in well with the Database framework, as some extra functionality which further abstracts away the database and the model. |
| ||
Clever! |
| ||
It'd be more clever were it finished, and it's only doing the "R" of CRUD. It probably also wants something similar to htbaa's ORM stuff to allow you to create more custom queries. Oh, and "p" is Null if no row is returned :-p |
| ||
This is a much nicer approach than my go at an ORM module. I did a easy SQL builder a while ago, which is on GitHub. It can generate easy SELECT/UPDATE/DELETE/INSERT queries. My ORM approach was buggy and got thrown into the bin. |
| ||
i've been playing with a framework as well. i didn't know you could attach metadata to the types ! that's awesome ... where is that documented ? anyway ... here is what i did ... the highlights are : *) i post an event to execute a query *) the event passes a query string, a "type" to map the data to, a callback function to receive the data when the query is done, and the params. *) the database code uses the column names in the query result to map to the fields of the passed in type, and creates instances and sets the field values from the result set. now that i understand that you can do metadata on your types ... i may take yet another stab at making my stuff even more generic. type tt_query field entity:ttypeid field query:string field callback(list:tlist) field params:tdbtype[] end type . . . local query:tt_query = new tt_query query.entity = ttypeid.forname("tt_apt") query.query = "SELECT * FROM APT_HDR WHERE ID LIKE ?" query.callback = callback_apt_list local param:tdbstring = new tdbstring param.setstring(gadgettext(_gg_tf_apt_id)) query.params = [param] createevent(event_id_db , EVENT_DB_SOURCE_QUERY , 0 , 0 , 0 , 0 , query ).emit() . . . case EVENT_DB_SOURCE_QUERY local query:tt_query = tt_query(_db_event_current.extra) if not _db_results then print "execute query" _query = TDatabaseQuery.Create(_db_c) _query.prepare(query.query) for local param:tdbtype = eachin query.params _query.addbindvalue(param) next _query.execute() if _db_c.hasError() runtimeerror("error on query") _db_results = createlist() end if if _query.nextrow() then local record:tqueryrecord = _query.rowrecord() local entity:object = query.entity.newobject() local count:int = record.count() for local idx:int = 0 to count-1 debugstop local columnfield:tqueryfield = record.getfield(idx) local efield:tfield = query.entity.findfield(columnfield.name) if efield select efield.typeid() case stringtypeid efield.setstring(entity , record.getstring(idx) ) case floattypeid efield.setfloat(entity, record.getfloat(idx)) end select end if next _db_results.addlast(entity) else ' emit event and cleanup print "query complete" query.callback(_db_results) _query = null _db_results = null _db_event_current = null end if Tony |