筆者在使用Entity Framework中的Scaffolding機制自動創建拓展名為mdf的資料庫及表單時,遇到如下的錯誤: 首先回顧一下創建這個程式的步驟: 1、創建一個Console控制台應用程式,程式集名稱及命名空間為ConsoleApp; 2、使用程式包控制台管理器將Entity Fra ...
筆者在使用Entity Framework中的Scaffolding機制自動創建拓展名為mdf的資料庫及表單時,遇到如下的錯誤:
A file activation error occurred. The physical file name '\\MusicDBContext.mdf' may be incorrect. Diagnose and correct additional errors, and retry the operation. CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
首先回顧一下創建這個程式的步驟:
1、創建一個Console控制台應用程式,程式集名稱及命名空間為ConsoleApp;
2、使用程式包控制台管理器將Entity Framework包含到此程式中,代碼如下:
PM> install-package Entity Framework
3、在App.Config文件中將以下內容插入到configuration節點:
<connectionStrings> <add name="MusicDBContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB; Initial Catalog=MusicDBContext;Integrated Security=SSPI; AttachDBFilename=|DataDirectory|\MusicDBContext.mdf" providerName="System.Data.SqlClient" /> </connectionStrings>
4、在控制台編寫以下代碼:
using System; using System.Linq; using System.Data.Entity; namespace ConsoleApp { class Program { static void Main(string[] args) { try { MusicDbContext db = new MusicDbContext(); Music music = new Music { Title = "Far Away From Home", ReleaseDate = DateTime.Now }; db.Musics.Add(music); db.SaveChanges(); db.Musics.ToList().ForEach(x => Console.WriteLine($"{x.ID}, {x.Title},{x.ReleaseDate}")); } catch (Exception ex) { Console.WriteLine(ex.Message); if(ex.InnerException != null) { Console.WriteLine(ex.InnerException.Message); } } Console.ReadKey(); } } public class Music { public int ID { get; set; } public string Title { get; set; } public DateTime ReleaseDate { set; get; } } public class MusicDbContext : DbContext { public MusicDbContext() : base("MusicDBContext") { } public DbSet<Music> Musics { set; get; } } }
5、運行此程式,發現程式不能按自己想要的結果運行,出現在最前面出現的錯誤。
通過查看出錯的信息,發現
AttachDBFilename=|DataDirectory|\MusicDBContext.mdf
有問題,而這又是沒有問題的,這到底是怎麼回事?為什麼會出現錯誤?
於是,通過MSDN查找相關資料,通過以下方法獲得DataDirectory指定的路徑是什麼:
object path = AppDomain.CurrentDomain.GetData("DataDirectory");
運行此行代碼,發現path居然是null!!!什麼?一般控制台或者Windows Form程式根據是Debug還是Release決定DataDirectory的初始化路徑為Bebug文件夾還是Release文件夾嗎?
這個錯了。
如果原先的Bebug文件夾或Release文件夾存在資料庫文件,使用類似"AttachDBFilename=|DataDirectory|\MusicDBContext.mdf"的寫法是沒有問題的,
即使path = null,它也知道是在Bebug文件夾或Release文件夾下。
如果原先的Bebug文件夾或Release文件夾不存在資料庫文件,上面的寫法就有問題,也就會出現最開始出現的那種錯誤。
那麼,我們該如何解決呢?細心的人可以發現,既然可以使用AppDomain.CurrentDomain.GetData來獲得DataDirectory指定的路徑,
那及可以使用AppDomain.CurrentDomain.SetData來指定DataDirectory的初始化路徑,代碼如下:
AppDomain.CurrentDomain.SetData("DataDirectory", Environment.CurrentDirectory);
通過以上的方法,就可以解決最開始前面的問題。
通過以上的介紹,最終的代碼修改如下:
using System; using System.Linq; using System.IO; using System.Data.Entity; namespace ConsoleApp { class Program { static void Main(string[] args) { string dbPath = Environment.CurrentDirectory + @"\MusicDBContext.mdf"; if(!File.Exists(dbPath)) { AppDomain.CurrentDomain.SetData("DataDirectory", Environment.CurrentDirectory); } try { MusicDbContext db = new MusicDbContext(); Music music = new Music { Title = "Far Away From Home", ReleaseDate = DateTime.Now }; db.Musics.Add(music); db.SaveChanges(); db.Musics.ToList().ForEach(x => Console.WriteLine($"{x.ID},{x.Title},{x.ReleaseDate}")); } catch (Exception ex) { Console.WriteLine(ex.Message); if(ex.InnerException != null) { Console.WriteLine(ex.InnerException.Message); } } Console.ReadKey(); } } public class Music { public int ID { get; set; } public string Title { get; set; } public DateTime ReleaseDate { set; get; } } public class MusicDbContext : DbContext { public MusicDbContext() : base("MusicDBContext") { } public DbSet<Music> Musics { set; get; } } }
程式就可以正常運行了。
註:
1)AttachDBFilename=|DataDirectory|\MusicDBContext.mdf
其中的“\”可以省略掉,即為:AttachDBFilename=|DataDirectory|MusicDBContext.mdf
2)如果是ASP.NET程式,DataDirectory的初始化目錄為App_Data。
3)關於更多的|DataDirectory|知識,請參考如下:
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/connection-strings