views:

410

answers:

6

A while ago I had a discussion with my colleagues about the persistence of Domain Models and whether we should enforce foreign-key constraints at the database level.

My first reaction was that the very use of a relational database implied the enforcement of such constraints, but some argued that the database should be seen as nothing but a persistence mechanism and therefore we should avoid placing any business logic in it. We ended up by not using foreign-key constraints.

Here is my question (I hope it is not too generic): is it considered good practice to enforce key constraints in theses cases?

+7  A: 

I think so, I consider it not as much something for business logic but preventing "bad" data from being entered into the database. Once the database becomes very large these constraints will prevent headaches in the future.

This will especially come into effect when you have multiple developers developing apps against the same data. This will ensure they as well can only enter valid data. Having constraints controlled in 1 spot instead of in x apps is certainly beneficial.

Chris Klepeis
I see your point. Thanks for taking the time to answer my question!
Saulo Silva
+3  A: 

I feel like ignoring really useful tools (database-level data integrity) for the sake of a pure development methodology is counter productive. Databases are REALLY good at this kind of thing...let them do it.

At some point every methodology begins to break down and you just have to be practical.

William Edmondson
+2  A: 

I used to think so, but my opinion has changed since I started writing a lot of resource-oriented systems. Typically, far more than just foreign key constraints are required to validate a piece of data - eg, a ticket that is in status "assigned" must have a valid "assigned_to" value, and so on. All of those rules should be placed in a validation routine of some sort, and while theoretically it might not hurt to have extra validation at the database level, if your app-level validation is working, checking the foreign key constraint is just wasted cycles. Much worse, though, you've now got logic about your data model repeated in two places - the validation code and the database constraints.

Think about it this way: would you want to move any other application logic in to the database (eg, via stored procedures) if you didn't have to? If you weren't forced to do so by performance considerations, I think the answer should generally be "no."

John Hyland
+1  A: 

"My first reaction was that the very use of a relational database implied the enforcement of such constraints, but some argued that the database should be seen as nothing but a persistence mechanism and therefore we should avoid placing any business logic in it. We ended up by not using foreign-key constraints."

Yes, well, the mediocre majority always wins that kind of debate by mere force of numbers, alas.

If you still want to fight that battle, you might ask your opponents how they intend to keep anyone from using "direct database editors" (ala db2-aid, spufi, ...) and how they intend to keep anyone from corrupting the database using such tools (which bypass their programmed business constraints by definition).

+1... why do people install a fully-featured relational database, then ignore pretty much every feature that it provides? Because they're scared of SQL and PL/SQL? "If you want a persistence mechanism, just write the data to a CSV file!"
Jeffrey Kemp
A: 

If you want to follow the Domain Driven Design paradigm, then the answer would be yes for anything within an Aggregate, and no for any cross-Aggregate links.

In nearly all cases, you want anything under the Aggregate Root to be deleted when the Root itself is deleted, and so having foreign keys that represent this, with cascading deletes, allow you to achieve this at the database level. You could also have your Repositories do the cascading deletes themselves if you didn't want to do it at a DB level, but the point still stands that Aggregate children should not exist without the Root.

For cross-Aggregate concerns, you'll probably be dealing with business decisions as to what should happen when one or the other is removed. Often you'll want to deal with this asynchronously to allow for scalability, and so your domain model ends up being eventually consistent. Therefore, it doesn't make sense in these cases to enforce foreign keys as there'll be a window of time where one or the other key may not exist.

Hope that helps! And for more info, definitely check out Evans' book on Domain Driven Design - and the many links around the web too.

Michael Hart
You say "When there is a window of time where one or the other key doesn't exist" ... Use deferred constraints, deferred constraints can solve this problem.
tuinstoel
I don't think that's correct - deferred constraints will still be checked when a transaction is committed. As each Aggregate Root is a separate consistency boundary, they could be operating in separate transactions (and you can't necessarily accommodate distributed transactions in a scalable system).What's needed here is Compensating Actions, and you need to define your business rules around how these should be handled.
Michael Hart
+5  A: 

Enforce constraints, but do NOT rely on them in your business logic

  • No business logic on the database: I agree with the principle. And if your non-SQL business code relies on the database constraints to check your database consistency, then you should rethink your business logic.
  • There is nothing wrong of having database constraints in addition to your business logic. Especially because things like referential integrity with FOREIGN KEYs and other UNIQUE constraints are easy to do and RDBMS are doing that job for you very efficiently without much maintenance.
  • Will you not use indices on the database too, because it is not purely persistency related?
  • Finding and fixing software bug may take you some time, but you definitely do not want to spend even more time cleaning up or (worse) loosing some data, just because you saved yourself a trouble of writing one-line script for a FK. Really: your get something for free here and your reject it?
  • [EDIT-1]: can you guarantee that the data in your database would be managed ONLY via your application? There always seem to be exceptions, mostly by power-users, who do sometimes (very rarely :-) make mistakes and execute some SQL statements to clean-up your code, update statuses (to invalid values because of typos) etc.
  • [EDIT-2]: Building domain driven model is not an excuse not to hire a good DB admin. Using ORM is not an excuse not to hire good DB developer.

But if you and your team are able to write bug-free software and handle all possible exception scenarios in your code (including hardware/network/dummy-user/programmer-error failures), then "Hei, why bother with redundant FK constraints...." - -teaser-

van
Interesting points there. Especially 3 and 5.
Saulo Silva
No business logic on the database sounds great, but what if the constraint is more efficiently implemented by the database? Would you still maintain this stance?
Abhijeet Kashnia