0

The problem I am trying to solve is not an overly complicated one but one that I would like to try and solve more elegantly than I currently am.

Problem:

We do business with multiple companies. For the sake of argument lets say each company produces motor vehicles. Each company has a differing implementation (i.e. data that must be persisted into a database). When a customer orders a car, you have no way of knowing what type of car they might buy so it is desirable to have a single looking table called 'Vehicles' that establishes the relationship between the CustomerId, a unique VehicleId, internal to our database, globally unique and some sort of composite key which would be unique in one of the many CompanyX_Vehicle tables.

An example would be:

Top level lookup table:

VehicleId
CustomerId
CompanyId
CompanyVehicleId

CompanyAVehicle Table:

CompanyAVehicleId ------> Part of composite key
CompanyId         ------> Part of composite key
...... unique implementation and persistence requirements.

CompanyBVehicle Table:

CompanyBVehicleId ------> Part of composite key
CompanyId         ------> Part of composite key
...... unique implementation and persistence requirements.

I have to disable foreign key enforcement for obvious reasons however in code (in this case C#, EF), I can perform a single query and eagerly include the necessary data from the correct CompanyXVehicle table.

Alternatively, I can omit any kind of relationship and just perform two queries each and every time, one to get the company and companyvehicle ID's and then make a call into the necessary table.

However I have a feeling there is a better alternative to either of these solutions. Does anyone have a suggestion on how to tackle this particular problem?

James Legan
  • 1,903
  • 2
  • 14
  • 21
  • You can learn about the different types of "subclassing" by reading about how an ORM like NHibernate does it. ex: http://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat AGain, you may not be using an ORM, but you can learn the ways-to-go-about-it from reading about it. TablePerType where your Type is a Company may be the right tree to bark up. – granadaCoder Oct 23 '15 at 02:27
  • @granadaCoder I just finished reading http://stackoverflow.com/questions/3579079/how-can-you-represent-inheritance-in-a-database TPT seems like the right way to go however I am concerned about the performance impacts. The project is using EF 6.x at the moment. – James Legan Oct 23 '15 at 03:00
  • I would suggest doing "object first" (poco) EF. Use EF to hydrate those objects. If you find a place or two where EF doesn't perform....move those back to IDataReader --> Manual ORM --> Poco objects....where the IDataReaders are populated with stored procedures. ORMs are "chatty" so usually they are ok...but have a backup plan (Idatareader/ado.net) for those spots if/where EF doesn't perform. Aka, object /poco first. That's my opinion....there will be many in that area. The key here is to create your tables with a known "pattern"...to which I think you are on the right track now. – granadaCoder Oct 23 '15 at 13:46

1 Answers1

0

I'll put an answer........so this can be closed out (eventually and if no one else puts a better answer).

While there are several ways to do this, I prefer the DRY method.

Which is :

Base Class/Table has the PK and all the scalars that are the same.

A different sub-class(table) for the different "types" of entities. This would have the scalars that are unique to the type.

Animal(Table)
AnimalSurrogateKey (int or guid)
Species (lookup table FK int)
Birthddate (datetime, null)


Dog(Table)
ParentAnimalSurrogateKey (int) PK,FK
BarkDecibels (int)

Snake(Table)
ParentAnimalSurrogateKey (int) PK,FK
ScaleCount (int)

Something like that.

ORMs can handle this. Hand/Manual ORM can handle it....

You can query for general information about the "Animals". Or you'll have multiple queries to get all the sub-type information.

If you needed to query about basic information about just Dogs, it would be

Select AnimalSurrogateKey , Species , Birthdate from dbo.Animal a where exists (select null from dbo.Dog d where d.ParentAnimalSurrogateKey = a.AnimalSurrogateKey )

..........

The key is to follow an established "pattern" for dealing with these scenarios. Most problems have already been thought out........and a future developer will thank you for mentioning in the comments/documentation "we implemented the blah blah blah pattern to implement".

APPEND:

(using info from http://www.sqlteam.com/article/implementing-table-inheritance-in-sql-server)

That is a great article going through the scenarios. Again, you'll have to judge if EF is "good enough" or not........if it isn't, then you can manually do your ORM ... and (to get around the multiple queries concern) ... maybe test a query like this .........

select p.PersonID , p.PersonTypeID , s.EnrollmentDate , t.HireDate , par.DifficultyScore
from dbo.People p 
left join dbo.Students s on p.PersonID = s.PersonID
left join dbo.Teachers t on p.PersonID = t.PersonID
left join dbo.Parents par on p.PersonID = par.PersonID

And then you can manually do your ORM to "switch/case" off of PersonTypeID, and create your subclasses using the data unique to each subclass (noting that the rows where the type is off, you will have null values.......ex: if your subtype is "Student", then par.DifficultyScore will be null for that row. )

At some point, you're gonna have to POC (proof of concept) your choice. You have a problem, there are a handful number of ways to deal with it....you have to test it. EF may be good enough..it may not be. Thus why I go POCO first...so I can go with ado.net/old-school/idatareaders if EF isn't performing well enough.

Good luck.

granadaCoder
  • 26,328
  • 10
  • 113
  • 146
  • I agree with the importance of the pattern which is why I am hesitating. In this particular case beyond the unique Id (Guid) that will be used by all consumers, the "Animal" table in your example would contain no useful information beyond that if the species. The key is that there are *zero* fields in common between the various species and the Animal table is there to serve as an abstraction/lookup. I also need to ensure that the Animal is only ever one species which is why I initially went the route of the composite key. Does that make sense? – James Legan Oct 23 '15 at 17:44
  • I came across this article, about half way down they discuss the way to achieve this however further articles go deep into the performance impacts. If I always have to perform a second query (since the base table holds no useful information about the specific implementation) is there a better way? This article seems to allow for that: http://www.sqlteam.com/article/implementing-table-inheritance-in-sql-server – James Legan Oct 23 '15 at 17:46
  • I appended my answer. No, I don't think there is a "better" way. Code the tables...try EF, if that doesn't work, fall back onto ado.net stored procedures. – granadaCoder Oct 23 '15 at 18:45