在项目中用程序中嵌入mdf文件的方式来进行sqlserver数据库教程开发非常方便,用来发布开源项目等很方便,点击就可以运行,免部署,特别是在教学中用起来更加方便,老师不用先将数据库文件detach再发给学生,学生也不用将数据库文件attach。采用项目中嵌入mdf文件的方式,老师把讲课的代码发给学生,学生打开就可以运行。教学中就是用的这种方式进行讲解。
在asp教程.net程序中只要将mdf文件放到项目的app_data文件夹即可,在连接字符串中使用
data source=.sqlexpress;attachdbfilename=|datadirectory|callcenter.mdf;integrated security=true;user instance=true
做连接字符串即可。
但是在winform程序中,如果在项目的app_data文件夹中新建一个mdf文件,然后用
data source=.sqlexpress;attachdbfilename=|datadirectory|callcenter.mdf;integrated security=true;user instance=true
进行连接会提示找不到callcenter.mdf。原来winform程序并不会去app_data中找mdf文件。原来在asp.net教程中datadirectory的值是当前项目的app_data路径,而winform中的datadirectory值则是当前项目的路径,因此winform中mdf文件不用放到app_data中,放到项目根目录下就可以。
但是新问题随之又来了,在winform中用这种方式开发的时候有时候改了项目中mdf文件中的表中的数据或者表结构,运行的时候却发现运行时通过程序读取的数据或者表结构没有变,而有时调试时insert插入的数据在这次调试的时候竟然没有了。经过研究发现,winform程序运行的时候连接的是bin/debug下的mdf文件,而不是项目中的mdf文件,这是和asp.net程序行为不同的地方。每次程序发生build行为的时候,项目中的mdf就会覆盖bing/debug下的mdf文件,也就是有两个mdf文件的存在,项目中的mdf相当于“源文件”。虽然可以通过修改文件的“buildtoouput”属性来部分解决问题,但是仍然不是很完美。
有一个比较很直接的想法,就是让程序去连接项目中的mdf文件,而不是连接bin/debug下那个。
经过查询资料找到了修改方法,在program.cs文件main函数最开始加入如下代码:
string datadir = appdomain.currentdomain.basedirectory;
if (datadir.endswith(@"bindebug")
|| datadir.endswith(@"binrelease"))
{
datadir = system.io.directory.getparent(datadir).parent.parent.fullname;
appdomain.currentdomain.setdata("datadirectory", datadir);
}
原理简单分析:连接字符串中的datadirectory的值就是通过appdomain.currentdomain.setdata赋值过去的,如果当前程序的目录以"bindebug"或者"binrelease"则认为它是运行在visualstudio环境中,就取项目的目录然后赋值给datadirectory这个key。既然是currentdomain.setdata,估计对于非默认appdomain中的数据库连接代码可能会不起作用(只是猜测,没验证),这就要需要创建子appdomain的时候再去赋值了。
上面的代码还是有一点潜在的bug的,比如正式的运行的时候exe被很杯具的放到了某个bindebug目录下,就会有问题,不过想想正式生产环境运行的时候肯定不会用这种attachdbfilename方式,这种方式只存在于开发环境,因此也就睁一只眼闭一只眼了