From: <jws...@ra...> - 2004-02-17 15:51:21
|
Having now worked with SQLOject a bit, I have a better idea of how I intend to use it and it's usefulness to my task. It appears that the fit is not complete, but I think that what I want is within the scope of what SQLObject aspires to be. I am working on a 3-tiered application with a relational storage at the bottom(Postgres), Business objects in the middle(SQLObject), and a presentation layer to be determined. The storage will be factored relentlessly, which means lots of small, specialized tables. I would like to use SQLObject to wrap up(join) those tables into convenient objects that can be manipulated. As an example, we want to have a customer account object in our app. That would be stored in the database as a number of tables- cust_account - main table buyer - contact name, relates to customer account buyer_info - contact address info, relates to buyer county - relates to customer shipping_rates - relates to customer Note that from the standpoint of the cust_account object, these are all one-to-one relations. It should be relatively simple to traverse these relations and present the attributes of the sub-tables as attributes of the root class. I will call these 'proxy attributes'. If x is an instance of our cust_account class, I should be able to do 'print x.email_addr' and get the address of the buyer back. Obviously this only works if there is one traversal path across the tables- one-to-one relationships. Exposing those proxy attributes as properties of the root object is in the object-oriented spirit of 'present the interface, hide the implementation'. There would need to be some way of handling duplicate column names. We could either mandate unique column names or provide a way to use aliases. I can imagine either reverse-engineering the database at compile-time with _fromDatabase or explicitly defining attributes and traversal paths. A conceptual difference is that I do not ever intend to create classes for minor tables. There will be objects for all the major components like employees and customers, and there will be objects like invoices that have a master-detail structure that will be exposed from attributes like 'line_items'. I will not be joining SQLObjects directly. Please comment. |
From: alexander s. <al...@an...> - 2004-02-17 16:46:25
|
jws...@ra... wrote, at 17.02.2004 17:46: > The storage will be factored relentlessly, which means lots of small, > specialized tables. I would like to use SQLObject to wrap up(join) those > tables into convenient objects that can be manipulated. As an example, we > want to have a customer account object in our app. That would be stored in > the database as a number of tables- > > cust_account - main table > buyer - contact name, relates to customer account > buyer_info - contact address info, relates to buyer > county - relates to customer > shipping_rates - relates to customer > > Note that from the standpoint of the cust_account object, these are all > one-to-one relations. if the relations are strict one-to-one, then why data is divided into separate tables? perhaps relationships may be optional, e.g. some customers are buyers, and others are not? if this is the case, then you may consider using SQLObject inheritance patch by Daniel Savard. > It should be relatively simple to traverse these > relations and present the attributes of the sub-tables as attributes of the > root class. I will call these 'proxy attributes'. If x is an instance of our > cust_account class, I should be able to do 'print x.email_addr' and get the > address of the buyer back. Obviously this only works if there is one > traversal path across the tables- one-to-one relationships. we did attribute delegation like this, but it did not play well, so we recently switched to class hierarchies. thanks Daniel! best wishes, alex. |
From: Ian B. <ia...@co...> - 2004-02-17 16:51:58
|
jws...@ra... wrote: > A conceptual difference is that I do not ever intend to create classes for > minor tables. There will be objects for all the major components like > employees and customers, and there will be objects like invoices that have a > master-detail structure that will be exposed from attributes like > 'line_items'. I will not be joining SQLObjects directly. For tables that will have no object representation, a join is probably the best idea -- RelatedJoin (many-to-many) is an example of this. For the one-to-one joins, I'm not really sure what would be best. In a way, it could almost be phrased like having a table named "table1, table2", and appending "table1.id=table2.id" to all your queries. At least, if you never want a distinct object representation of one table vs. the other. Though in that case, the utility of the separate tables is questionable -- is it really one-to-zero-or-one? Well, then the table name is "table1 left join table2 on table1.id=table2.id", with column names that include the table reference -- even easier! All very hackish though. And since you are using Postgres, views are another possibility. I don't much care for them, but they seem like a good fit to what you're doing. Ian |
From: Luke O. <lu...@me...> - 2004-02-17 16:57:47
|
> cust_account - main table > buyer - contact name, relates to customer account > buyer_info - contact address info, relates to buyer > county - relates to customer > shipping_rates - relates to customer > > Note that from the standpoint of the cust_account object, these are all > one-to-one relations. It should be relatively simple to traverse these > relations and present the attributes of the sub-tables as attributes of the > root class. I will call these 'proxy attributes'. If x is an instance of our > cust_account class, I should be able to do 'print x.email_addr' and get the > address of the buyer back. Obviously this only works if there is one > traversal path across the tables- one-to-one relationships. Exposing those > proxy attributes as properties of the root object is in the object-oriented > spirit of 'present the interface, hide the implementation'. There would need > to be some way of handling duplicate column names. We could either mandate > unique column names or provide a way to use aliases. Yes, so long as these are all one-to-one, it makes sense. I don't think there's a need for worrying about unique column names, that's something you need to resolve at your main object interface level. Any automated aliasing scheme would seem to expose implementation in awkward ways. But I could be wrong. > A conceptual difference is that I do not ever intend to create classes for > minor tables. There will be objects for all the major components like > employees and customers, and there will be objects like invoices that have a > master-detail structure that will be exposed from attributes like > 'line_items'. I will not be joining SQLObjects directly. I think you may have an issue here. What benefits are you getting from SQLObject if you don't model those 'private' tables? I have similar database setups (presenting multiple tables as unified objects), and model the entire implementation. When you say you don't want to create objects for all tables, I'm thinking you don't want your implementation-specific objects to be part of your public interface, but I don't think you're going to get the ease of implementing these proxies in SQLObject without having private objects for every relevant table. class CustomerAccount(SQLObject): # private composition _buyer = ForeignKey('Buyer') # public proxy def _get_emailAddr(self): # this could also have proxy at Buyer obj to buyerInfo, so like: # return self._buyer.emailAddr == return self._buyer.buyerInfo.emailAddr makes this work: x = CustomerAccount(id) print x.emailAddr Now, we could probably make this Proxy/Composition concept more automatic, whether with nested classes or a Col-like object with name->proxyCol mappings: class CustomerAccount(SQLObject): # nested class Buyer(SOProxy): _proxyClass = 'Buyer' # defaults from class name? # with second-level proxy as above emailAddr = 'emailAddr' # or emailAddr = 'buyerInfo.emailAddr' # col-like, have to be smart about multiple proxies to same class. emailAddr = Proxy('Buyer', 'buyerInfo.emailAddr') Does this fit into your goals? No matter what, I don't see how you're going to get around your middle layer explicitly describing these mappings from the database implementation to your chosen public object interface. - Luke |