一步步开发自己的博客 .NET版(9、从model first替换成code first 问题记录)

为什么要改用code first

用过code first的基本上都不会再想用回model first或是db first(谁用谁知道)。不要问我为什么不一开始就直接使用code first,因为那个时候我还不会(甚至还把model first当成了code first)。

因为工作中使用的就是code first,且越用越习惯,越用越喜欢。

原因如果:

  • 再也用为每次生成那个笨重的edmx文件性急了
  • 再也不用当心保存tt文件而丢失特性、注销、扩展方法了
  • 再也不用为了使用微软的验证插件非得写Metadata文件了
  • 再也不用为了扩展tt文件生成的实体类去写(partial)部分类了。
  • 再也不用为了生成满足自己需要的实体而去修改那些坑爹的tt文件里面的语法代码了(如:默认每个实体继承一个父类)
  • 再也不用为了查找edmx文件打不开,去编辑庞大的edmx文件中找那些坑爹的错误了。
  • 等等还有些暂时没想到的....

说改就改

修改前实体: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=&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; }
    }

然后重新命令: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; }
    }

然后重新命令: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

时间: 2024-10-13 21:59:31

一步步开发自己的博客 .NET版(9、从model first替换成code first 问题记录)的相关文章

一步步开发自己的博客 .NET版(4、文章发布功能)百度编辑器

前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做个插件,任何网站上的技术文章都可以转发收藏 到本博客. 所以打算写个系类:<一步步搭建自己的博客> 一.一步步开发自己的博客  .NET版(1.页面布局.blog迁移.数据加载) 二.一步步开发自己的博客  .NET版(2.评论功能) 三.一步步开发自己的博客  .NET版(3.注册登录功能) 四

一步步开发自己的博客 .NET版 剧终篇(6、响应式布局 和 自定义样式)

前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做个插件,任何网站上的技术文章都可以转发收藏 到本博客. 所以打算写个系类:<一步步搭建自己的博客> 一步步开发自己的博客  .NET版(1.页面布局.blog迁移.数据加载) 一步步开发自己的博客  .NET版(2.评论功能) 一步步开发自己的博客  .NET版(3.注册登录功能) 一步步开发自己

一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)

前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做个插件,任何网站上的技术文章都可以转发收藏 到本博客. 所以打算写个系类:<一步步搭建自己的博客> 一步步开发自己的博客  .NET版(1.页面布局.blog迁移.数据加载) 一步步开发自己的博客  .NET版(2.评论功能) 一步步开发自己的博客  .NET版(3.注册登录功能) 一步步开发自己

一步步开发自己的博客 .NET版(1、基本显示)

前言 我们每个猿都有一个搭建自己独立博客的梦,我也不例外.以前想 现在想 以后也想.之所以一直迟迟没有着手,是因为难以跨出第一步.每次心里想着,等我以后技术好了再说,然后就没有然后了.以前用过wordpress,虽然插件很多,不过有时候想改改自己想要的效果很难,因为 我压根就不会php.也看过.net的一些开源博客,代码量多,看得头晕,没那个耐心. 再说,别人的始终是别人的.得鱼不如得渔.与其花时间去研究php还不如自己写个.net版的.有人说博客园已经很好了啊,我承认确实,而且还可以后台定制自

一步步开发自己的博客 .NET版(10、前端对话框和消息框的实现)

关于前端对话框.消息框的优秀插件多不胜数.造轮子是为了更好的使用轮子,并不是说自己造的轮子肯定好.所以,这个博客系统基本上都是自己实现的,包括日志记录.响应式布局等等一些本可以使用插件的.好了,废话不多时.我们来实现自己的对话框和消息框. 对话框 要求:可拖动.点击按钮后可回调 画一个简单的模型框 <div class="hi-dialog-box clearfix"> <div class="hi-dialog-title">系统提示<

一步步搭建自己的博客 .NET版(3、注册登录功能)

前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做个插件,任何网站上的技术文章都可以转发收藏 到本博客. 所以打算写个系类:<一步步搭建自己的博客> 一.一步步搭建自己的博客  .NET版(1.页面布局.blog迁移.数据加载) 二.一步步搭建自己的博客  .NET版(2.评论功能) 三.一步步搭建自己的博客  .NET版(3.注册登录功能) 四

开源分享:用Python开发的开源博客系统Blog_mini

本博文在51CTO技术博客首发. 开源不易,Python良心之作,真心送给广大朋友,恳请给予支持,不胜感激! 0.Blog_mini送给你们:让每个人都轻松拥有可管理的个人博客 你从未架设过服务器或网站,希望可以接触一下这方面的知识-- 你从未使用过Linux操作系统,希望可以接触一下这方面的知识-- 你是初中生/高中生/大学生,希望能在学业之余锻炼一下自己的IT技能-- 你是Python新手,希望能有一个用Python开发的个人博客-- 你学习Python许久,希望有一个开源的项目可以用来学习

iOS开发个人独立博客收集

现在国内技术博客网站有很多,如CSDN,CNBlog,ITEye等,论坛的话主要是要cocachina.这里是我收集的iOS开发个人独立博客,文章用搜索引擎比较难搜到,都是牛人: OneV's Den 简介:一个在日本工作的清华哥哥,写的文章有深度 唐巧 简介:粉笔网,iOS主程 zhenby's blog 简介:技术牛人 "我"的开发笔记 简介:专注于iOS.web 技术奇异点 简介:文章太有深度了,基本都在系统层 Kevin Cao's Blog 简介:一个具有艺术家气质的,IT创

Node.js 从零开发 web server博客项目

第1章 课程介绍 包括课程概述.核心模块.核心技术.课程安排.课程收获.讲授方式.学习前提等方面的介绍,让同学们对课程项目有一个直观的了解. 1-1 课程导读 试看第2章 nodejs 介绍 本章主要为了照顾尚未入门或者刚刚入门 nodejs 的同学,介绍 nodejs 的下载.安装和基本使用,以及 nodejs 和前端 javascript 的区别.另外,重点介绍了服务端开发和前端开发思路上的区别,为后续的开发做一个基础的铺垫. 2-1 下载和安装 2-2 nodejs和js的区别 2-3 c