一步步开发本身的博客 .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 

相关文章
相关标签/搜索