i initiate this topic and named it ''frustrated'' cause reading
the WO
doc i was thinking : "It would be cool if active record was that  
smart" ...
On 17 juin 05, at 09:06, Simon Stapleton wrote:
> Hi.
>
> First off, let me say that I come from a WebObjects background (the  
> ObjC version, not that horrible Java stuff) and I miss the ability  
> to do inheritance ''other than the one-table way'' 
I''m learning to
> work around it, but I _do_ still miss it.
>
> There are 3 approaches to inheritance mapping in general use, _and  
> none of them is perfect for every situation_.
>
> I happen to have the WebObjects 4.5 docs in front ot me, which have  
> as good a description as any, so I''ll cut and paste fairly freely:
>
> Note that the Apple examples are based on Employee is a Person,  
> Customer is a Person, and as noted in previous discussions, this  
> does not deal with Employee Customers - however, such a case is a  
> different domain model and should be dealt with differently.
>
>
>
>>>> Vertical Mapping
>>>>
>>>>
>> In this approach, each class has a separate table associated with  
>> it. There is a Person table, an Employee table, and a Customer  
>> table; each table contains only the attributes defined by that class.
>>
>> This method of storage directly reflects the class hierarchy. If  
>> an object of the Employee class is retrieved, data for the  
>> Employee''s Person attributes must be fetched along with
Employee
>> data. The relationship between Employee and Person is resolved  
>> through a join to give Employee access to its Person data. This is  
>> also true for Customer.
>>
>>
>>> Advantages
>>>
>>>
>> With vertical mapping, a subclass can be added at any time without  
>> modifying the Person table. Existing subclasses can also be  
>> modified without affecting the other classes in the class  
>> hierarchy. The primary virtue of this approach is its clean,  
>> "normalized" design.
>>
>>
>>> Disadvantages
>>>
>>>
>> Vertical mapping is the least efficient of all of the approaches.  
>> Every layer of the class hierarchy requires a join to resolve the  
>> relationships. For example, if you want to do a deep fetch from  
>> Person, three fetches are performed: a fetch from Employee (with a  
>> join to Person), a fetch from Customer (with a join to Person),  
>> and a fetch from Person to retrieve all the Person attributes. (If  
>> Person is an abstract superclass for which no objects are ever  
>> instantiated, the last fetch is not performed.)
>>
>>
> Note that efficiency here is only an issue for relational  
> databases, if you use postgres or another object-relational dbms  
> you can have the joins effectively for free by defining inherited  
> tables.  Also note that the last parenthesised part of that  
> discussion is misleading, Person must always be fetched as long as  
> it has attributes defined)
>
> This could be ''faked'' in RoR in several ways:
>
> - under postgres, use table inheritance, don''t implement the
''type''
> column and make your base class ''abstract''. 
That''s only going to
> work where the base class is never instantiated, thought, and would  
> only work under psql.  Thinking about it, you could probably not  
> make the base class abstract, but you''d need to be careful about  
> what accessors try to do.  Need to think about this more.
>
> - under a ''generic'' database, define the base class as
per STI (the
> ''rails way'') then define ''details''
tables for each subclass.
> subclass your base class as usual and each one has_a :foo_details.   
> Deal with accessors on the details tables by delegating.  Not   
> perfect and doesn''t allow (easy) searching on subclass attributes
>
>
>
>>>> Horizontal Mapping
>>>>
>>>>
>> In this approach, you have separate tables for Employee and  
>> Customer that each contain columns for Person. The Employee and  
>> Customer tables contain not only their own attributes, but all of  
>> the Person attributes as well. If instances of Person exist that  
>> are not classified as Employees or Customers, a third table would  
>> be required (where Person is not an abstract class). In other  
>> words, with horizontal mapping every concrete class has a self- 
>> contained database table that contains all of the attributes  
>> necessary to instantiate objects of the class.
>>
>> This technique entails the same fetching pattern as vertical  
>> mapping, except that no joins are performed.
>>
>>
>>
>>> Advantages
>>>
>>>
>> Similar to vertical mapping, a subclass can be added at any time  
>> without modifying other tables. Existing subclasses can also be  
>> modified without affecting the other classes in the class hierarchy.
>>
>> This approach works well for deep class hierarchies, as long as  
>> the fetch occurs against the leaves of the class hierarchy  
>> (Employee and Customer) rather than against the root (Person). In  
>> the case of a deep fetch, it''s more efficient than vertical  
>> mapping (since no joins are performed). It''s the most
efficient
>> approach, if you only fetch instances of one leaf subclass at a time.
>>
>>
>>
>>> Disadvantages
>>>
>>>
>> Problems may occur when attributes need to be added to the Person  
>> superclass. The number of tables that need to be altered is equal  
>> to the number of subclasses-the more subclasses you have, the more  
>> effort is required to maintain the superclass. However, if table  
>> maintenance happens far less often than fetches, this might be a  
>> viable approach for your application.
>>
>>
> You can do this one in rails easily enough.  Don''t define a
''type''
> attribute and you''re away.  If you''re really crafty, and
your
> database supports it, you can define the ''tables'' as
views on joins
> to a hierarchy of tables as per Vertical Mapping and all should be  
> well (with the possible exception of primary key generation, I''m  
> not sure about that)
>
>
>
>>> Single Table Mapping
>>>
>>>
>> In this approach, you put all of the data in one table that  
>> contains all superclass and subclass attributes. Each row contains  
>> all of the columns for the superclass as well as for all of the  
>> subclasses. The attributes that don''t apply for each object
have
>> NULL values. You fetch an Employee or Customer by using a query  
>> that just returns objects of the specified type (the table would  
>> probably include a type column to distinguish records of one type  
>> from the other).
>>
>>
>>> Advantages
>>>
>>>
>> This approach is faster than the other two methods for deep  
>> fetches. Unlike vertical or horizontal mapping, you can retrieve  
>> superclass objects with a single fetch, without performing joins.  
>> Adding a subclass or modifying the superclass requires changes to  
>> just one table.
>>
>>
>>> Disadvantages
>>>
>>>
>> Single table mapping can consume an inordinate amount of space  
>> since every row includes columns for every one of the other  
>> entities'' attributes. This may depend on how your database
stores
>> NULLs. Some databases condense NULL values, thereby reducing the  
>> storage space needed, but some databases maintain the length of  
>> the actual data type of the column regardless of the value stored.  
>> Most databases also have limitations on how many columns a table  
>> can have (typically this is around 250 columns), which can make it  
>> impossible to use single table mapping for a deep class hierarchy  
>> that has lots of instance variables.
>> Also, if you have a lot of data, this approach can actually be  
>> less efficient than horizontal mapping since with single table  
>> mapping you have to search the entire table to find the rows  
>> needed to instantiate objects of a particular type. (Horizontal  
>> mapping is only more efficient if your application just fetches  
>> one type of leaf object at a time (instances of a particular  
>> subclass).
>>
>>
> Rails does this.
>
> Oddly enough, the Apple docs don''t mention the most crippling  
> limitation of Single Table mapping; that you generally can''t  
> enforce row consistency using database constraints, as pretty much  
> all attributes and relationships that aren''t part of the base
class
> become optional.  This is not a problem as long as your database is  
> accessed _only_ by your app, but as soon as other apps start  
> getting their sticky fingers in the tables, life gets dangerous  
> _fast_.
>
> For me, the lack of a decent, database agnostic, approach for  
> vertical mapping is a pain.  Not as much of a pain as the problems  
> with date handling, but hey.  It''s on my list too.
>
> Simon
>
> And finally, as an aside, that CustomerEmployee thing.  It''s a red
> herring.  None of the inheritance mechanisms described deal with it  
> - in fact, if you needed to deal with it, you wouldn''t want to  
> model it as inheritance, at least not directly.  Here''s one way I
> might do it (ignoring inheritance mechanisms because they are  
> irrelevant).  If the emphasis of the system was different, one  
> might invert the status of Employee and Customer, or indeed treat  
> them both as optional relationships on Person.
>
> class Person
>
>     has_one :customer_reference, :dependent => true
>
>     has_one :contact_detail
>
>     etc etc
>
>     def self.customers
>
>         self.find(:all).reject{|p| p.customer_reference.nil?}
>
>     end
>
> end
>
> class Employee < Person
>
>     has_many :employment_history
>
>     etc etc
>
> end
>
> class NonEmployee < Person
>
> end
>
> class CustomerReference
>
>     belongs_to :person
>
>     has_many :purchase_history
>
>     has_one :credit_card
>
>     etc etc etc
>
> end
> _______________________________________________
> Rails mailing list
> Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>
>