一步步開發本身的博客 .NET版(九、從model first替換成code first 問題記錄)

爲何要改用code first

用過code first的基本上都不會再想用回model first或是db first(誰用誰知道)。不要問我爲何不一開始就直接使用code first,由於那個時候我還不會(甚至還把model first當成了code first)。html

由於工做中使用的就是code first,且越用越習慣,越用越喜歡。git

緣由若是:sql

  • 再也用爲每次生成那個笨重的edmx文件性急了
  • 不再用小心保存tt文件而丟失特性、註銷、擴展方法了
  • 不再用爲了使用微軟的驗證插件非得寫Metadata文件了
  • 不再用爲了擴展tt文件生成的實體類去寫(partial)部分類了。
  • 不再用爲了生成知足本身須要的實體而去修改那些坑爹的tt文件裏面的語法代碼了(如:默認每一個實體繼承一個父類)
  • 不再用爲了查找edmx文件打不開,去編輯龐大的edmx文件中找那些坑爹的錯誤了。
  • 等等還有些暫時沒想到的....

說改就改

修改前實體:db first(由tt文件生成)數據庫

修改後實體:code first(徹底手寫)ide

而後把實體更新到數據庫對應的表結構。執行命令Enable-Migrations函數

遇到問題:ui

 The EntityFramework package is not installed on project ''.(緣由:由於沒有選擇「默認項目」)spa

繼續問題:.net

 

 The project 'Blogs.Model' failed to build.(緣由:沒有建一個繼承於DbContext的類)插件

 

 ok,提示已經啓用遷移。

而後咱們執行命令:Add-Migration blogs

異常: 從數據庫中獲取提供程序信息時出錯。這多是 Entity Framework 使用的鏈接字符串不正確致使的。有關詳細信息,請查看內部異常並確保鏈接字符串正確。

個人乖乖,我很是肯定咱們字符串連接是正確的啊。

最後肯定忘記給數據鏈接上下文在構造函數中傳入配置文件的數據庫連接名。

  public BlogDbContext()
            : base("HiBlogsTest")
        {
        }

 

再執行(Add-Migration blogs),再出錯:

 

 異常:沒法加載指定的元數據資源。(百度之,原來是連接字符串有問題。http://www.cnblogs.com/chengxiaohui/articles/2106765.html

 <add name="HiBlogsTest" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;
         provider connection string=&quot;
         data source=.;
         initial catalog=HiBlogsTest;
         user id=sa;
         password=123qwe;
         MultipleActiveResultSets=True;
         App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

 

改爲:(那一堆csdl、ssdl、msl什麼都不要了,就留個簡單的連接。乾淨)

<add name="HiBlogsTest" connectionString="Data Source=.;Initial Catalog=HiBlogsTest;User ID=sa;Password=123qwe;" providerName="System.Data.SqlClient" />

 

ok,終於沒有看見紅色的字了。

且看到了一個自動生成的blogs文件。且無論,看看數據庫是否有表結構。

空空如也。(屁都沒看到一個)(緣由:BlogDbContext上下文中沒有添加實體,沒有告訴程序要生成哪些實體到數據庫)

給BlogDbContext類添加數據代碼:

  public class BlogDbContext : DbContext
    {
        public BlogDbContext()
            : base("HiBlogsTest")
        {
        }       
        public DbSet<BlogInfo> BlogInfos { get; set; }
        public DbSet<BlogComment> BlogComments { get; set; }
        public DbSet<BlogReadInfo> BlogReadInfos { get; set; }
        public DbSet<BlogTag> BlogTags { get; set; }
        public DbSet<BlogType> BlogTypes { get; set; }
        public DbSet<BlogUser> BlogUsers { get; set; }
        public DbSet<BlogUserInfo> BlogUserInfos { get; set; }
    }

 

而後執行 :Add-Migration blogs 再執行 update-database

終於看到表數據了。

有了表還不行,咱們尚未主外鍵。

修改BlogDbContext以下:

public class BlogDbContext : DbContext
    {
        public BlogDbContext()
            : base("HiBlogsTest")
        {
        } 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            var entityBlogUser = modelBuilder.Entity<BlogUser>();

            entityBlogUser.HasMany(p => p.BlogInfos).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId")); 
          
            entityBlogUser.HasRequired(p => p.BlogUserInfo).WithRequiredPrincipal(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId")); 

            entityBlogUser.HasMany(p => p.BlogTags).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId"));

            entityBlogUser.HasMany(p => p.BlogTypes).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId"));

            entityBlogUser.HasMany(p => p.BlogComments).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId"));

            var entityBlogInfo = modelBuilder.Entity<BlogInfo>();

            entityBlogInfo.HasMany(p => p.BlogTags).WithMany(t => t.BlogInfos)
           .Map(m => m.ToTable("BlogInfo_BlogTag"));

            entityBlogInfo.HasMany(p => p.BlogTypes).WithMany(t => t.BlogInfos)
            .Map(m => m.ToTable("BlogInfo_BlogType"));

            entityBlogInfo.HasMany(p => p.BlogComments).WithRequired(t => t.BlogInfo)
              .Map(m => m.MapKey("BlogInfoId"));

            entityBlogInfo.HasMany(p => p.BlogReadInfos).WithRequired(t => t.BlogInfo)
             .Map(m => m.MapKey("BlogInfoId")); 
        }


        public DbSet<BlogInfo> BlogInfos { get; set; }
        public DbSet<BlogComment> BlogComments { get; set; }
        public DbSet<BlogReadInfo> BlogReadInfos { get; set; }
        public DbSet<BlogTag> BlogTags { get; set; }
        public DbSet<BlogType> BlogTypes { get; set; }
        public DbSet<BlogUser> BlogUsers { get; set; }
        public DbSet<BlogUserInfo> BlogUserInfos { get; set; }
    }
View Code

 

而後從新命令:Add-Migration blogs 再執行 update-database

又見錯誤:

將 FOREIGN KEY 約束 'FK_dbo.BlogInfo_dbo.BlogUser_BlogUserId' 引入表 'BlogInfo' 可能會致使循環或多重級聯路徑。請指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其餘 FOREIGN KEY 約束。
沒法建立約束。請參閱前面的錯誤消息。

因而,一個一個的外鍵刪掉,又一個個的來建。終於發現:(下圖是數據庫關係圖,mssql生成的

百度之:(原來是爲了約束聯級刪除數據作的約束。實在話,還沒玩過聯級刪除了,說明這個需求應該不是很經常使用。找個方法禁用能否?)

直接加一個.WillCascadeOnDelete(false)就能夠了。(http://www.cnblogs.com/chear/archive/2012/11/09/2762145.html

public class BlogDbContext : DbContext
    {
        public BlogDbContext()
            : base("HiBlogsTest")
        {
        } 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            var entityBlogUser = modelBuilder.Entity<BlogUser>();

            entityBlogUser.HasMany(p => p.BlogInfos).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId")).WillCascadeOnDelete(false);
            //與上面等效
            //modelBuilder.Entity<BlogInfo>().HasRequired(p => p.BlogUser).WithMany(t => t.BlogInfos)  

            //以BlogUser爲主表(BlogUserInfo爲從表,創建外鍵)
            entityBlogUser.HasRequired(p => p.BlogUserInfo).WithRequiredPrincipal(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId")).WillCascadeOnDelete(false);
            //等效於HasRequired(p => ).WithOptional(i => );

            ////以BlogUserInfo爲主表(BlogUser爲從表,創建外鍵)
            //modelBuilder.Entity<BlogUser>().HasRequired(p => p.BlogUserInfo).WithRequiredDependent(t => t.BlogUser) 
            //.Map(m => m.MapKey("BlogUserId")).WillCascadeOnDelete(false);
            //等效於 HasOptional(p => ).WithRequired(i => ); 

            entityBlogUser.HasMany(p => p.BlogTags).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId")).WillCascadeOnDelete(false);

            entityBlogUser.HasMany(p => p.BlogTypes).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId")).WillCascadeOnDelete(false);

            entityBlogUser.HasMany(p => p.BlogComments).WithRequired(t => t.BlogUser)
            .Map(m => m.MapKey("BlogUserId")).WillCascadeOnDelete(false);

            var entityBlogInfo = modelBuilder.Entity<BlogInfo>();

            entityBlogInfo.HasMany(p => p.BlogTags).WithMany(t => t.BlogInfos)
           .Map(m => m.ToTable("BlogInfo_BlogTag"));

            entityBlogInfo.HasMany(p => p.BlogTypes).WithMany(t => t.BlogInfos)
            .Map(m => m.ToTable("BlogInfo_BlogType"));

            entityBlogInfo.HasMany(p => p.BlogComments).WithRequired(t => t.BlogInfo)
              .Map(m => m.MapKey("BlogInfoId")).WillCascadeOnDelete(false);

            entityBlogInfo.HasMany(p => p.BlogReadInfos).WithRequired(t => t.BlogInfo)
             .Map(m => m.MapKey("BlogInfoId")).WillCascadeOnDelete(false); 
        }


        public DbSet<BlogInfo> BlogInfos { get; set; }
        public DbSet<BlogComment> BlogComments { get; set; }
        public DbSet<BlogReadInfo> BlogReadInfos { get; set; }
        public DbSet<BlogTag> BlogTags { get; set; }
        public DbSet<BlogType> BlogTypes { get; set; }
        public DbSet<BlogUser> BlogUsers { get; set; }
        public DbSet<BlogUserInfo> BlogUserInfos { get; set; }
    }
View Code

 

而後從新命令:Add-Migration blogs 再執行 update-database

完美,表結構過來了。表關係過來了。(接下來就是該代碼了,由於表名作了小的改動,字段也作了少量調整因此改的東西還真很多。整整改了一天時間。)

如今回過頭來想一想,以前是先model first以後小許改動就用的db first。之前怎麼沒有遇到過(將 FOREIGN KEY 約束 'FK_dbo.BlogInfo_dbo.BlogUser_BlogUserId' 引入表 'BlogInfo' 可能會致使循環或多重級聯路徑。請指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其餘 FOREIGN KEY 約束。
沒法建立約束。請參閱前面的錯誤消息。)這個錯誤。好奇心驅使,以爲看看之前的代碼的edmx是怎麼管理這種關係的。

很驚奇的發現,徹底沒有問題。因而,不死心看看數據庫裏面是否是有什麼蹊蹺。

搜噶,原來如此。經過model first生成的主外鍵關係默認就沒有設計聯級刪除,而code first默認設置就是聯級刪除。

 

以上內容,都是我胡說八道。謝謝您的閱讀,但願對您有那麼一點點做用。

Hi-Blogs源碼地址:http://git.oschina.net/zhaopeiym/Hi-Blogs

最近由於工做實在太慢,開源博客長久沒有更新。今天忽然來回翻了好幾遍,發現半年前的本身寫的代碼是如此的不堪入目。

今天僅僅只是把db first改爲了code first,發黴的代碼我還得找個時間好好重構重構。

首發地址:http://www.cnblogs.com/zhaopei/p/5540532.html 

相關文章
相關標籤/搜索