用過code first的基本上都不會再想用回mode first或是db first(誰用誰知道)。不要問我為什麼不一開始就直接使用code first,因為那個時候我還不會(甚至還把mode first當成了code first)。
因為工作中使用的就是code first,且越用越習慣,越用越喜歡。
原因如果:
再也用為每次生成那個笨重的edmx檔案性急了
再也不用當心儲存tt檔案而丢失特性、登出、擴充方法了
再也不用為了使用微軟的驗證插件非得寫Metadata檔案了
再也不用為了擴充tt檔案生成的實體類去寫(partial)部分類了。
再也不用為了生成滿足自己需要的實體而去修改那些坑爹的tt檔案裡面的文法代碼了(如:預設每個實體繼承一個父類)
再也不用為了查找edmx檔案打不開,去編輯龐大的edmx檔案中找那些坑爹的錯誤了。
為什麼要改用code first
用過code first的基本上都不會再想用回model first或是db first(誰用誰知道)。不要問我為什麼不一開始就直接使用code first,因為那個時候我還不會(甚至還把model first當成了code first)。
- 等等還有些暫時沒想到的....
說改就改
修改前實體:db first(由tt檔案生成)
修改後實體:code first(完全手寫)
然後把實體更新到資料庫對應的表結構。執行指令Enable-Migrations
遇到問題:
The EntityFramework package is not installed on project ''.(原因:因為沒有選擇“預設項目”)
繼續問題:
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="
data source=.;
initial catalog=HiBlogsTest;
user id=sa;
password=123qwe;
MultipleActiveResultSets=True;
App=EntityFramework"" 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; }
}
完美,表結構過來了。表關系過來了。(接下來就是該代碼了,因為表名做了小的改動,字段也做了少許調整是以改的東西還真不少。整整改了一天時間。)
現在回過頭來想想,之前是先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
- 學習本是一個不斷抄襲、模仿、練習、創新的過程。
- 雖然,園中已有本人無法超越的同主題博文,為什麼還是要寫。
- 對于自己,博文隻是總結。在總結的過程發現問題,解決問題。
- 對于他人,在此過程如果還能附帶幫助他人,那就再好不過了。
- 由于部落客能力有限,文中可能存在描述不正确,歡迎指正、補充!
- 感謝您的閱讀。如果文章對您有用,那麼請輕輕點個贊,以資鼓勵。
- 工控物聯Q群:995475200