This is a (actually it is several) follow-up question to my previous question on F# Type Providers and Continuous Integration.
It seems to me that it would be a good idea to use the SqlDataConnection
type provider as a compile-time check that the code/database integrity remains intact in feature-branch driven development; you would know at every commit/build that no changes have been made to the code that has not also been applied to the database, assuming that building the database is also a part of your CI process.
However, a couple of questions arise:
The name (as well as the location) of the config file is not the same at compile time as at runtime, e.g. app.config -> MyApp.exe.config, which will result in a runtime error if you try to use
SqlDataConnection<ConnectionStringName="DbConnection", ConfigFile="app.config">
(Actually, specifying
ConfigFile="app.config"
is not necessary, since it is the default value.)The runtime error can be avoided by copying the app.config file to the output directory (there’s a setting for that), but that would result in having both an app.config and a MyApp.exe.config file in the output directory. Not very pretty. Adding a separate configuration file for type providers would be another solution, but imho that’s not very pretty either.
Question: Has anyone come up with a more elegant solution to this problem?
The next problem arises when you come to the build server. It is most likely that you don’t want to compile against the same database as you did while developing, thus requiring a different connection string. And yes, in production you’d need yet another one.
Question: How do you go about solving this in the most convenient way? Remember, the solution has to be a working part of a CI process!
This strategy would require generating the database on each build at the build server, probably from a baseline script with some feature/sprint update scripts.
Question: Has anyone tried this and how did it affect build times? If yes, how did you create this step?
I am familiar with the solution that @Gustavo proposes, but I’ve always felt that there is something fishy about it. Something about having to specify the connection string twice… However, when I once again got the same reply, I slowly started to realize that the answer must be correct, and that it’s me who’s thinking wrong. These are my conclusions: The reply states that you can use the GetDataContext overload that accepts a connection string. If you change this to should, things become clearer, at least to me.
The thing is that I’ve been thinking of the class definition as both a compile-time directive and as a run-time variable, but even though this is possible, it is hardly a good idea. The default value of the ConfigFile argument is as we’ve already seen “app.config”, but that file doesn’t exist (with that name) at run-time, so it doesn’t make sense to try to use it, thus leaving GetDataContext as the only reasonable option. I suggest that you do this:
Keep your compile-time settings in a file called compilation.config (or whatever you prefer) and specify this file for usage in the class definition.
Use the GetDataContext overload that accepts a connection string for run-time resolution and specify this connection string in the app.config file.
You will end up with something looking like this:
Heck, this even supports the SRP; compile-time settings in one file and run-time settings in another!
Regarding the rest of my questions, I assume that the answer lies in some scripting in the Continuous Deployment pipeline. Still interested in other solutions though.
At runtime you can use the
GetDataContext
overload that accepts a connection string. See here: Providing connection string to Linq-To-Sql data provider