For better or worse, we have a solution that relies on multiple databases that all reference a common administration database. Databases ship as part of modules, and not al
We have such a modularity in our products, but our database requirements are merged together during installtion. For example our admin package and product A may be the initial purchase by a client where they install the two modules into database X. If they later buy product B the database component is layered right on top of database X adding in the DRI where necessary.
The only case where I have seen the need for separate databases from a design perspective is when you are drawing a hard line between business units (such as a corporation) at which point the issue is really a type of partitioning. Great Plains Dynamics does this where they have a single administrative database, and multiple corporation databases. However each module in GP for a given corporation resides in that single database.
Of course if you are stuck with separate databases, I would agree that D is the best option.
I wonder if SQL Server has a feature like Oracle's materialized views? This is an object that you define with a query like a view, but the results of the query get stored as a table. There are then various mechanisms for automatically refreshing.
If there is such a feature, I would suggest making a materialized view of the core table(s) in each satellite database. Then you can reference that in your foreign keys. The main issue would be whether it can be refreshed frequently enough for your needs.
You can address this in a number of ways architecturally in order to funnel all changes through a central service so that they are not able to make inconsistencies, but regardless of how much effort you are willing to put into that (and creating a bottleneck or single point of failure may violate some other requirements you have) you will not be able to rely on the database engine itself to enforce it with a guarantee like you can with a FK constraint.
I often had to deal with this in cross-departmental database situations where things could get out of sync because disparate systems were not fully integrated yet, or security concerns required them to have separate administrators.
In these cases, I usually rely on exception reports generated hourly, which check on the status of things and only report if there is a problem. The SQL Server Agent jobs have powerful scheduling capabilities. I always used log tables and SQLAnswersMail to generate nice little HTML emails (where URL links in the emails could even take you to administration pages to correct the problems) to the various system administrators, but there are tons of ways to skin this cat.
I think that the funny thing.. is that you could make a small MS Access copy of your database, enforce RI in Access.. and then upsize, and Microsoft Access gives you the option to choose between using Triggers or DRI.. and I'm pretty certain that Microsoft Access will write the core parts of the triggers for you.
While we're on the topic, I hate MS Access.. but the one thing that is superior with Access, is that you can enforce RI against a QUERY (sql select, aka view).. I really wish that MS SQL Server had that same functionality.
You should implement a Service Oriented Architecture. Where the different services in the system are running with their on database schema. Then let you applications run independently from any databases but let them run against the services.
Depending on your database implementation, often you will be able to link tables from another database (the AdminDB) and have them appear in your various module databases.
In Microsoft Access you can link tables by right clicking, and then choosing an ODBC data source. In Oracle they call it a database link. I'm willing to bet SQLServer has some form of this implementation short of implementing custom replication on a single table.
Once you link in your foreign admin tables to your module databases (or vice versa), then you should be able to define constraints as if the tables were within the same schema.
A second option may be even simpler. What if you used the same schema for all modules and admin database? You know the admin database is present, so simply run the table creation script against that schema. As long as there is no table / view / stored procedure naming conflicts, then it should all work just by changing the dblogin in all modules to match.