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
>
>