Mixing of mapping strategies in a hierarchy

Posts   
 
    
tprohas
User
Posts: 257
Joined: 23-Mar-2004
# Posted on: 15-Sep-2005 04:27:22   

I have a FrontBrake entity that I created from Brake using a discriminator column and now I can't have Brake inherit from ProductVersion. Take the following example, why can't we do this? Lets say I want to have FrontBrake, Brake, ProductVersion as my hierarchy. In the generated code I see this as the hierarchy; FrontBrake -> Brake -> EntityBase2, then ProductVersion -> EntityBase2. Why can't we do FrontBrake -> Brake -> ProductVersion? This would be mixing types, but I don't see why it can't be done.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 15-Sep-2005 15:17:13   

tprohas wrote:

I have a FrontBrake entity that I created from Brake using a discriminator column and now I can't have Brake inherit from ProductVersion. Take the following example, why can't we do this? Lets say I want to have FrontBrake, Brake, ProductVersion as my hierarchy. In the generated code I see this as the hierarchy; FrontBrake -> Brake -> EntityBase2, then ProductVersion -> EntityBase2. Why can't we do FrontBrake -> Brake -> ProductVersion? This would be mixing types, but I don't see why it can't be done.

Mapping strategies are not mixable as it would complicate the inner structure tremendously, and it was already a huge undertaking to get it all in. So I opted for first no mixing of mapping strategies, and add it later.

The other reason I didn't add it was that it's highly unlikely you will run into a requirement to mix mapping strategies: at the point where the mix takes place, you both have a hierarchy based on a discriminator column and a PK which is an FK to another table's PK.

Then back to your model. I have a bit of a hard time understanding why a physical object like Brake, which is a part, or product, is a subtype of 'productversion'. Isn't 'Brake' a product, which has a version? IMHO this is about semantics, but what you have to understand is that if you define a row of data to be of a given type, you can't change that type afterwards. If you think you need to change it afterwards, (dreaded example: employee<-manager<-boardmember, manager gets promoted to boardmember. This can't be done, so the model is in fact not good. This for example runs the risk of the 'Person <- employee and Person<-customer' problem, where employee is also a customer), it's not a candidate to be in a hierarchy.

Frans Bouma | Lead developer LLBLGen Pro
tprohas
User
Posts: 257
Joined: 23-Mar-2004
# Posted on: 15-Sep-2005 21:26:02   

Otis wrote:

tprohas wrote:

I have a FrontBrake entity that I created from Brake using a discriminator column and now I can't have Brake inherit from ProductVersion. Take the following example, why can't we do this? Lets say I want to have FrontBrake, Brake, ProductVersion as my hierarchy. In the generated code I see this as the hierarchy; FrontBrake -> Brake -> EntityBase2, then ProductVersion -> EntityBase2. Why can't we do FrontBrake -> Brake -> ProductVersion? This would be mixing types, but I don't see why it can't be done.

Mapping strategies are not mixable as it would complicate the inner structure tremendously, and it was already a huge undertaking to get it all in. So I opted for first no mixing of mapping strategies, and add it later.

The other reason I didn't add it was that it's highly unlikely you will run into a requirement to mix mapping strategies: at the point where the mix takes place, you both have a hierarchy based on a discriminator column and a PK which is an FK to another table's PK.

Then back to your model. I have a bit of a hard time understanding why a physical object like Brake, which is a part, or product, is a subtype of 'productversion'. Isn't 'Brake' a product, which has a version? IMHO this is about semantics, but what you have to understand is that if you define a row of data to be of a given type, you can't change that type afterwards. If you think you need to change it afterwards, (dreaded example: employee<-manager<-boardmember, manager gets promoted to boardmember. This can't be done, so the model is in fact not good. This for example runs the risk of the 'Person <- employee and Person<-customer' problem, where employee is also a customer), it's not a candidate to be in a hierarchy.

I understand what your saying about a product which has a version. The way I setup my table structure I have Product (abstract) <- Brake (part version) -> ProductVersion (abstract version). I am trying to use the part specific table (Brake) as the top of the hierarchy which is the specific part version, I would then have to map the properties from Product into the part specific entities. This way when I query for brakes I get all the version specific results of brake. This is where I want to extend the problem and create FrontBrake and RearBrake based on a discriminator column. Does this make sense or am I doing things backwords?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 16-Sep-2005 13:50:59   

tprohas wrote:

I understand what your saying about a product which has a version. The way I setup my table structure I have Product (abstract) <- Brake (part version) -> ProductVersion (abstract version). I am trying to use the part specific table (Brake) as the top of the hierarchy which is the specific part version, I would then have to map the properties from Product into the part specific entities. This way when I query for brakes I get all the version specific results of brake. This is where I want to extend the problem and create FrontBrake and RearBrake based on a discriminator column. Does this make sense or am I doing things backwords?

I think you use an instance version (productversion) as a type, which IMHO is a mistake. A Brake instance has a version, it's not a version. Or am I mistaken?

See it as: you have 'Department' as base entity type. If you model your organisation, you might think, 'I have a marketing department, an engineering department etc.'. But if you have just 1 of them, you probably are just using attribute VALUES of the actual type as a reason to create a new type.

FrontBrake and RearBrake, I can imagine if you want these as different types, though consider them only as types if you give one different fields than the other (or a couple of different fields). If not, you're making things more complicated than it is: testing in memory if an instance is a frontbrake or a readbrake, is easier made by testing a field value than a type check using 'is' or gettype().

Inheritance should be used to give entities different / extra fields, relations over their supertypes. Like 'Manager <- Boardmember', where you have a relation between boardmember and companycar, so a manager doesn't have that relation. Inheritance makes it possible to define that. Without it, you would have to define the relation on manager and have a boolean or role type perhaps in the entity which signals what the row actually means (manager or boardmember)

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 16-Sep-2005 15:41:23   

Also, like I mentioned in a previous thread, you generally don't create a derived class due to attribute differences but for behavior differences.

See the book Object Thinking for a very good discussion on this.

BOb

tprohas
User
Posts: 257
Joined: 23-Mar-2004
# Posted on: 16-Sep-2005 23:04:06   

pilotboba wrote:

Also, like I mentioned in a previous thread, you generally don't create a derived class due to attribute differences but for behavior differences.

See the book Object Thinking for a very good discussion on this.

BOb

By this you mean that my Brake inheriting ProductVersion is wrong. Instead of having a Brake table that holds the attributes specific to an instance of a brake and the ProductVersion table that holds the attributes for all versions of all products, I should duplicate the ProductVersion attributes in all the Product specific tables like brake. I do understand this, and the reason I didn't do this is because I didn't want to have to duplicate the ProductVersion fields in 40 product specific tables like Brake, FrontBrake, RearBrake, BottomBracket etc. Also, whenever a new part is added to the system I would again have to duplicate these fields for the new part.

pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 17-Sep-2005 00:11:39   

tprohas wrote:

pilotboba wrote:

Also, like I mentioned in a previous thread, you generally don't create a derived class due to attribute differences but for behavior differences.

See the book Object Thinking for a very good discussion on this.

BOb

By this you mean that my Brake inheriting ProductVersion is wrong. Instead of having a Brake table that holds the attributes specific to an instance of a brake and the ProductVersion table that holds the attributes for all versions of all products, I should duplicate the ProductVersion attributes in all the Product specific tables like brake. I do understand this, and the reason I didn't do this is because I didn't want to have to duplicate the ProductVersion fields in 40 product specific tables like Brake, FrontBrake, RearBrake, BottomBracket etc. Also, whenever a new part is added to the system I would again have to duplicate these fields for the new part.

I'm not really sure, I'd have to study your domain model more before I made a specific Object Model recomendation.

My point was for example, a FrontBrade is a Brake while is a Part. But, that doesn't mean that those are seperate objects unless they have different behaviors. So, I wouldn't create a FrontBreak and a RearBreak type that inheriet from Brake. They just (to me, but I don't know your domain) don't have different behaviors they just have different attributes.

A simple example of a model we all know better.

A Person has an attribute of EyeColor. Some people have blue eyes, some have brown eyes. Also, you could say a Brown Eyed Person is a Person. But, that doesn't mean you go and create a Brown Eyed Person class that derives from Person.

What should differentiate items in an object hierarchy are the behaviors.

So, if you can create a property of a class, each different value can be different but the type doesn't change. Where as, if you create a method of a class the subclass needs to implement that method differently than the parent class (different behavior.) Or, the subclass needs to have a beharior that a parent class doesn't have (different behavior).

This is actually something you can't map in LLBLGen for example a strategey pattern. For example, an entity might have an attribute which is a behavior. So, the attribute of your entity might be an Interface and you use some type of strategy to determine what concert class will provide that interface's implementation for the property. As far as I know you also can't map an Interface in LLBLGen. (You can in NHibernate.).

It may be that ProductVersion is an Interface that all your parts would implement so that each Part would have an IProductVersion which is perhaps implemented by Brake or whatever. Once again, I don't know your domaim model well enough, I am just talking in generalalites here.

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 17-Sep-2005 11:18:21   

pilotboba wrote:

tprohas wrote:

pilotboba wrote:

Also, like I mentioned in a previous thread, you generally don't create a derived class due to attribute differences but for behavior differences.

See the book Object Thinking for a very good discussion on this.

BOb

By this you mean that my Brake inheriting ProductVersion is wrong. Instead of having a Brake table that holds the attributes specific to an instance of a brake and the ProductVersion table that holds the attributes for all versions of all products, I should duplicate the ProductVersion attributes in all the Product specific tables like brake. I do understand this, and the reason I didn't do this is because I didn't want to have to duplicate the ProductVersion fields in 40 product specific tables like Brake, FrontBrake, RearBrake, BottomBracket etc. Also, whenever a new part is added to the system I would again have to duplicate these fields for the new part.

I'm not really sure, I'd have to study your domain model more before I made a specific Object Model recomendation.

My point was for example, a FrontBrade is a Brake while is a Part. But, that doesn't mean that those are seperate objects unless they have different behaviors. So, I wouldn't create a FrontBreak and a RearBreak type that inheriet from Brake. They just (to me, but I don't know your domain) don't have different behaviors they just have different attributes.

There is a difference between entity supertype/subtype inheritance and class inheritance. The main reason is that an entity doesn't have behavior defined, a class does. In code, you use inheritance to alter behavior OR/AND alter class fields. In a relational model, you use inheritance to define relations and new attributes.

The difference isn't big in practise, as developers tend to focus on data first anyway, but it's there nevertheless.

A simple example of a model we all know better.

A Person has an attribute of EyeColor. Some people have blue eyes, some have brown eyes. Also, you could say a Brown Eyed Person is a Person. But, that doesn't mean you go and create a Brown Eyed Person class that derives from Person.

What should differentiate items in an object hierarchy are the behaviors.

THough, you do need to if you want to create a relation between BrownEyedPerson and the BrownEyedPersonClub entity, a club for BrownEyedPersons simple_smile . To create that relation solely for brown eyed persons, you create a new subtype in your relational model, browneyedperson, define a relation between that subtype and BrownEyedPersonClub and it's done. That's not change in behavior per se (or you could call it that, I'm not sure if you mean with behavior also these kind of things). I added this example to illustrate that supertype/subtype hierarchies in relational models can have a different problem to solve than classes do.

So, if you can create a property of a class, each different value can be different but the type doesn't change. Where as, if you create a method of a class the subclass needs to implement that method differently than the parent class (different behavior.) Or, the subclass needs to have a beharior that a parent class doesn't have (different behavior).

This is actually something you can't map in LLBLGen for example a strategey pattern. For example, an entity might have an attribute which is a behavior. So, the attribute of your entity might be an Interface and you use some type of strategy to determine what concert class will provide that interface's implementation for the property. As far as I know you also can't map an Interface in LLBLGen. (You can in NHibernate.).

I have the feeling you think in code inheritance too much, which isn't the way you should be looking at it. Interfaces area a way to define multiple type inheritance in code. Interfaces are a phenomenon only found in single-implementation-inheritance languages like C# or VB.NET or Java.

In a relational model, I can have multiple inheritance, in code I can't. I decided not to go for the multiple-inheritance for now, as it's very complicated to build a correct relational model which supports multiple inheritance. For example, you have to define multiple FK constraints on a single set of fields, which is in theory odd and wrong: one PK table is enough to define referential integrity. It's also not that common, and degrades performance alot due to the many joins which have to take place.

Btw, I'm not aware that nhibernate allows you to map interfaces and also query against them (Hibernate 3 doesn't do that IMHO, just classes).

In 1.0.2005.1, you can't define an interface which is implemented by a hierarchy of elements and query against that interface. You can query for supertypes and get the polymorphic results back, like querying for 'Part' and get 'Brake', 'Frame' etc. I know DataObjects.NET supports interface mapping and they have it as a prominent feature, but I have yet to run into an example where I needed it.

It may be that ProductVersion is an Interface that all your parts would implement so that each Part would have an IProductVersion which is perhaps implemented by Brake or whatever. Once again, I don't know your domaim model well enough, I am just talking in generalalites here.

Versioned elements are a problem on their own: the version is part of the PK, so a part isn't identified by its own ID, you also need a versionid to identify the actual part.

What would be good to know is when a part gets a new version. What are the criteria for that? Is that vendor driven or is that caused by the fact that a part simply gets updated and probably has new properties?

Though lets not forget: all this starts by simply designing a model in an abstract way, for example using NIAM/ORM. It's a simple technique: just define sentences: Part Has Version, Brake Is Part, Bike Needs Frame, etc.

You can use a free tool for that: Download page microsoft.com You could for example reverse engineer your current model and see if you can adjust it a bit or correct it.

Frans Bouma | Lead developer LLBLGen Pro
tprohas
User
Posts: 257
Joined: 23-Mar-2004
# Posted on: 29-Sep-2005 19:24:04   

I didn't really want to continue this, but had to add in that when I use the word "Version" as in ProductVersion I'm not referring to version as a new/changed version of a product. I am using the word version to mean something more like a different color or price of a product.

bmoeskau
User
Posts: 54
Joined: 15-Jun-2005
# Posted on: 23-Oct-2006 07:31:19   

I think I'm running into the same kind of issue where I would ideally want to mix both types of inheritance, but please Frans if you can suggest a better data model I'm all ears. simple_smile

We have a root table (BaseItem) that has all the fields common to all entities (CreatedBy, Description, etc.). We have a CalendarItem that is a subtype of BaseItem, and has a set of a dozen or so extra fields specifically related to calendar processing (start date, end date, timezone, etc.). This is implemented currently as a subtype via TargetPerEntity, since these are separate tables and are related on BaseItem.ID(PK) - CalendarItem.ID(FK).

The issue now is that CalendarItem should really be abstract, and I want to create entities of type Event and Task that both map exactly to CalendarItem, but will have slightly different behavior, business rules, etc. While we could implement these also via TPE, that would require separate tables for each subtype, even though the attributes would be exactly the same. It seems to me that this is perfectly suited to TargetPerEntityHierarchy so that I could simply create these as subtypes mapped directly on CalendarItem, but I can't do that unless I unmap CalendarItem from its TPE relationship to BaseItem.

So we have: BaseItem <- CalendarItem <- Event | Task

I predict that you're going to tell me either: A) add all BaseItem fields to CalendarItem (this would be a duplication of 15-20 fields) and create two separate hierarchies via TPEH, or B) add tables for Event and Task that only have a FK column so that I can continue mapping everything via TPE (the easiest for us).

What would be your recommended approach for this hierarchy?

[Edit]: One more things I forgot to mention is that Event and Task would ideally be further borken down into subtypes. E.g., Event can be a regular Event, or a Birthday (that has separate logic). There's a rule that a Contact can have exactly 1 Birthday, so ideally I would have a 1:1 relation from Contact to Birthday. Do I really have to create a new table every time I want to introduce a strongly-type subtype in TPE? That's the whole beauty of TPEH is that you can easily add type variations without exploding the data model. But if you go with TPEH, you lose all the nice relations that are already in the DB. I want both!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 23-Oct-2006 12:18:30   

bmoeskau wrote:

I think I'm running into the same kind of issue where I would ideally want to mix both types of inheritance, but please Frans if you can suggest a better data model I'm all ears. simple_smile

We have a root table (BaseItem) that has all the fields common to all entities (CreatedBy, Description, etc.). We have a CalendarItem that is a subtype of BaseItem, and has a set of a dozen or so extra fields specifically related to calendar processing (start date, end date, timezone, etc.). This is implemented currently as a subtype via TargetPerEntity, since these are separate tables and are related on BaseItem.ID(PK) - CalendarItem.ID(FK).

The issue now is that CalendarItem should really be abstract, and I want to create entities of type Event and Task that both map exactly to CalendarItem, but will have slightly different behavior, business rules, etc. While we could implement these also via TPE, that would require separate tables for each subtype, even though the attributes would be exactly the same. It seems to me that this is perfectly suited to TargetPerEntityHierarchy so that I could simply create these as subtypes mapped directly on CalendarItem, but I can't do that unless I unmap CalendarItem from its TPE relationship to BaseItem.

So we have: BaseItem <- CalendarItem <- Event | Task

I predict that you're going to tell me either: A) add all BaseItem fields to CalendarItem (this would be a duplication of 15-20 fields) and create two separate hierarchies via TPEH, or B) add tables for Event and Task that only have a FK column so that I can continue mapping everything via TPE (the easiest for us).

Definitely: A.

The reason is that if you use a central base entity in the database, it will hurt performance, as for every query you do, you'll have joins with that base item. As your model gets bigger and more and more data will be added to the db, this will hurt you sooner or later.

This is discussed in the documentation in the pitfalls section of Concepts -> Entity inheritance and relational models

What's more efficient is to have the base item as an associated entity to calendar. So it's not a hierarchy, but the fields are separated into a different table.

However, that's pretty meaningless. You see: the sharing you have of base-item's fields isn't that common in relational models. If you look closely, you didn't focus on defining Calendar's entity and the attributes of that, but grouped the attributes Calendar has in common with other entities into a separate entity. This isn't correct as they don't form a separate entity: 'baseitem' isn't a real entity, it's used to group a set of attributes which are shared among other entities, but the relations with other entities is always strong: there's no baseitem without another record in another table, e.g. calendar. This is a signal that the model is somewhat odd, as the baseitem is on the PK side and should have a weak relation with the subtype tables.

There's an explanation of course why the model is like you have it: in classes you'd define BaseItem and derive the rest from BaseItem, and it's perfectly logical. However, in relational models, this will lead to problems with performance sooner or later. That's not a problem of LLBLGen Pro's internal code, it's unavoidable.

That's also why I think it's important to understand that, even though you're using an O/R mapper and the mismatch between classes and relational models should be abstracted away from you, the mismatch is there and if the two models (class model vs. relational model) are way different, performance will decrease, no matter what. So it's important to realize that having a central root entity which is the base of every other entity, it can lead to performance problems after a while, so it's good to design with that in mind.

What would be your recommended approach for this hierarchy? [Edit]: One more things I forgot to mention is that Event and Task would ideally be further borken down into subtypes. E.g., Event can be a regular Event, or a Birthday (that has separate logic). There's a rule that a Contact can have exactly 1 Birthday, so ideally I would have a 1:1 relation from Contact to Birthday. Do I really have to create a new table every time I want to introduce a strongly-type subtype in TPE? That's the whole beauty of TPEH is that you can easily add type variations without exploding the data model. But if you go with TPEH, you lose all the nice relations that are already in the DB. I want both!

Having mixed hierarchies is very cumbersome to implement and even slower in final results. The main reason is that for every row that comes back, the hierarchy can change so checks which type is represented by the row is slower to determine. As the scope of these mixed hierarchies is small, I decided not to implement it as it would eat a tremendous amount of time away from the project time.

One of the pitfalls documented in the documentation is 'Don't map instance variantions as hierarchies':

Don't map instance variations as hierarchies. While this is a grey area, it's important to note that if you have variations in instances based on semantical interpretation of the data and there aren't likely to be very many instances of a given 'type', it might be better to not create these subtypes. An example can be if you have a 'Department' entity and you create a 'Marketing' subtype of that Department entity and from that a MarketingEurope, MarketingUSA, MarketingAsia etc. subtypes. These last subtypes are actually instances of Marketing, not real subtypes.

I think you should take a step back and think about what's an entity and what's an attribute. IMHO 'Birthday' isn't an entity, it's an attribute (normally). In your situation, I can understand it's a type of item you can add to a calendar, but then it falls into the pitfall of Instance variantion, and it shouldn't be a subtype IMHO.

Frans Bouma | Lead developer LLBLGen Pro
bmoeskau
User
Posts: 54
Joined: 15-Jun-2005
# Posted on: 23-Oct-2006 14:30:36   

Frans, thanks for your lengthy response.

So, how would you model this? BaseItem literally has 18 columns that are common to every primary entity in our model. We currently have 7 entities that link to BaseItem by PK. We understand the trade-off in join performance, but without BaseItem we would have an additional ~120+ columns to manage spread across 7 different tables (with more entities to come). It sounds like this is what you are recommending based on this comment?

If you look closely, you didn't focus on defining Calendar's entity and the attributes of that, but grouped the attributes Calendar has in common with other entities into a separate entity. This isn't correct as they don't form a separate entity

That seems like it will become unmanageable as we continue to add more entities with the same base set of columns.

Also, our system requires some flexibility in terms of querying for items somewhat generically. In terms of our domain, a contact could be related to events or tasks, etc., a member can have contacts, events, tasks, etc., an event can have contacts, notes, etc. In object terms (I realize that's different from data model) we can basically have arbitrary hierarchies among items of different types. To achieve that, we have a single table that joins BaseItems to other BaseItems, and one that joins BaseItems to our Members. That gives us everything we need in most cases. Wouldn't the alternative in this case be that we'd essentially have to prefetch (join to) every single table in order to execute a query that could bring back any given entity type?

To try and understand your recommendation, our entities currently are modeled in this hierarchy via Target per Entity:

BaseItem |_ Bookmark |_ CalendarItem ......|_ Event ......|_ Task |_ Contact |_ InventoryItem |_ Note

I think you are saying scrap the existing hierarchy altogether and model the main 5 as completely separate entities, adding all fields from BaseItem into every other table. Then for CalendarItem, map Event and Task onto it using Target per Entity Hierarchy. Is this the way you see it?

I think you should take a step back and think about what's an entity and what's an attribute. IMHO 'Birthday' isn't an entity, it's an attribute (normally). In your situation, I can understand it's a type of item you can add to a calendar, but then it falls into the pitfall of Instance variantion, and it shouldn't be a subtype IMHO.

I agree, but... if Birthday has different behavior (it's a specific event type that is 1:1 to a Member or Contact, it has specific rules built in, etc.) then how do I still get the class I need in the object model if I don't have an entity in the data model? Would you still recommend only having Event and just using naming standards for calling birthday-specific properties? Again, in object terms, I would normally create multiple interfaces to Event so that I can deal with a strong type, but I am struggling with transferring the concept over to how I should model it for LLBL.

Again, thank you very much for the help. Our goal is to do things the best way if we can just get our arms wrapped around it simple_smile

Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 24-Oct-2006 17:08:27   

Hi,

I think that as long as you really need to set up specific relations and fields, you can derive new tables, child or simple related (you should not make hierarchies when aggregation is more apropriate, if you don't need the base object attributes systematically, or if the joins performance is an issue ).

Now you still have to decide which attributes desserve to be structuraly enforced in the DB, especially if high performance is important and development time is limited, since LLBLGen generator's ease of use may drive you wrongly into designing a whole bunch of your object model in DB, which is a dangerous bias, unless you need extreme flexibility and can afford the overhead.