EF--CodeFirst

EF框架有三种基本的方式:DB First,Model First,Code First。这里简单的说一下Code First,适合没有基础的同学照着做,学习基础的东西。

通过Code First我们可以在还没有建立数据库的情况下就开始编码,然后通过代码来生成数据库。

1、还是先建立一个类库项目。(这里忘了说了,和前面两个模式一样,这里我使用的工具是:VS2013,sqlserver2008r2)

然后创建4个类,这几个类表示数据库中的表的列的定义

public class User
    {
        public Guid Id { set; get; }
        public string Name { set; get; }
        public int Age { set; get; }
        public Guid RoleId { set; get; }
    }
    public class Role
    {
        public Guid Id { set; get; }
        public string Name { set; get; }
    }
    public class Right
    {
        public Guid Id { set; get; }
        public string Name { set; get; }
    }
    public class UserRight
    {
        public Guid UserId { set; get; }
        public Guid RightId { set; get; }
    }

2、创建数据库访问的上下文,以便对数据库进行增删改查。上下文中的属性表示数据库中的表

public class CodeFirstContext : DbContext//这个DbContext必须要添加EntityFramework 5.0的引用才能编译通过
    {
        public DbSet<User> UserSet { get; set; }
        public DbSet<Role> RoleSet { get; set; }
        public DbSet<Right> RightSet { get; set; }
        public DbSet<UserRight> UserRightSet { get; set; }      

    } 

3、在类Class1中定义增删改查的方法,这里与前面两个模式中的Class1是一样的,我就不再重复了,这里只简单的添加一个用于增加数据的函数

public class Class1
    {
        public int AddUser(){
        User u = new User(){
               Id=Guid.NewGuid(),
               Name = "Bali",
               Age=32
            };
        CodeFirstContext con = new CodeFirstContext();
        try
        {
            con.UserSet.Add(u);
            con.SaveChanges();
        }
        catch (Exception e)
        {
            return 0;
        }
        return 1;
    }
 }

4、创建一个控制台项目,调用class1中的AddUser函数,运行,这时候需要等待一下,最后看到执行的结果报错了

意思就是找不到数据库。EF默认的数据库是:.\SQLEXPRESS,如果本地没有SQLEXPRESS,EF会尝试LocalDb\v11.0(包含在VS2012中) 

在上面几步中,没有一点是关于数据库的,没有添加链接字符串,所以需要在控制台项目的配置文件中添加如下代码:

<connectionStrings>
<add name="CodeFirstContext" providerName="System.Data.SqlClient" connectionString="Server=.;Database=CodeFirst;User ID = sa;Password = 123456;Trusted_Connection=False"/>
</connectionStrings>

这个链接字符串的名称是CodeFirstContext,就是数据库上下文的名称

同时,需要对CodeFirstContext类添加一个构造函数,让上下文能找到数据库:

public CodeFirstContext() : base("name=CodeFirstContext") { }

这个时候系统会提示缺少System.Data.Entity的引用,因此要添加上这个引用才行

5、再次执行,结果又报错

这里就会发现,之前在定义实体的时候,都没有指定键值和外键(如果有的话),但是为什么偏偏是最后一个实体报错了,前面几个没问题。

Code First会默认将以类似Id结尾来命名的属性当作主键,如ID,Id,本例中的Id都自动设置为主键。如果该属性是int类型,Code First会在数据库中默认将该列设置为自增长。

在UserRight实体中没有Id属性,因此系统找不到该让谁来做主键,因此报错。这个问题的解决方案,网上有很多,这里就不做探讨,在此,只做简单的介绍,将遇到的问题解决了。

如果想要更深的学习,可以参考:http://www.cnblogs.com/caofangsheng/p/5023696.html

首先是要添加引用

将UserRight类重新设计,这是复合主键的设置方式,如果是单一主键,只需添加[Key]即可。

public class UserRight
    {
        [Key]
        [Column(Order = 1)]
        public Guid UserId { set; get; }
        [Key]
        [Column(Order = 2)]
        public Guid RightId { set; get; }
    }

6、运行,这次是成功了,在添加的user表的时候,没有设置RoleId,但是在数据库中可以看到,这列是系统默认值。这里还有很多的属性约束没有谈到,比如name的类型为什么

是nvarchar(max)而不是nvarchar(50),为什么name可以为空,而roleid和age却不能为空。这里也不做探讨了,相关的资料网上有。

 

 7、至此,codefirst模式的基本流程算是走一遍了。那么现在问题来了,如果这个时候数据库里面有数据了,需要添加新的表,或者给表添加列,删除列,或者修改列的类型。

常规的思路是直接在项目中添加实体,然后再次运行。

先添加一个实体

public class Company
    {
        public Guid Id { set; get; }
        public string Name { set; get; }
        public string Address { set; get; }
    }

然后在上下文类中添加一个属性public DbSet<Company> CompanySet { get; set; }      

再运行,结果报错

 

 

8、下面介绍数据迁移

8.1、

 

在程序包管理器控制台,执行语句:Enable-Migrations或Enable-Migrations –EnableAutomaticMigrations

结果出现了错误:无法将“Enable-Migrations”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。

然后输入Get-Package,发现未安装程序包,输入安装命令Install-Package EntityFramework还是有错,发现程序包源和默认项目没有按照图中的设置

改过来后就成功安装了

安装完成后,发现上面的EF版本变成最新的6.1.3版了,同时添加了sqlserver的引用。

8.2、输入Enable-Migrations –EnableAutomaticMigrations

命令完成后,此时在项目中创建一个Migrations文件夹。该文件夹保存着迁移的升级脚本,记录着一些迁移配置,大部分的时候无需关注。这一步只需要在第一次操作的时候干,平时无需管它。

 8.3、输入Update-Database –Verbose。这样就完成了数据库迁移

可以看到,companies表已经创建了,而且还多了个__MigrationHistory表,这个不用管它。它里面有如下数据

可以看到ef版本的变化。

9、这时候我们又对实体进行修改

这个时候再次执行Update-Database –Verbose,结果报错

执行Update-Database –Verbose -force,这个时候就成功了,但是问题也来了。首先看数据库

数据库的表结构确实如愿以偿的修改了,但是看看users表中的数据,结果数据丢失了

 

大部分的时候只需要进行如下两步即可:

  1. 将包管理器的默认项目切换到模板项目
  2. 在程序包管理器中执行 Update-Database –Verbose

不过,还有如下几个地方需要注意一下: 

有损升级:如果我们进行了如删除列,限制数据精度的时候,这个时候升级的时候就会出现错误提示,遇到这种情况,首先确保升级是安全的,然后通过增加-force参数强制升级。或者直接修改Configuration.cs的AutomaticMigrationDataLossAllowed选项,放开有损升级检查。(不大建议)

不兼容的升级:如果我们进行了加入了非空列,要进行数据转换等不兼容的升级的时候,自动升级会失败,这个时候则需要和传统的迁移方式那样构造升级代码,比较麻烦,且容易出错。如果没有特殊需求不建议进行不兼容的升级。

 

 

从上面的步骤看来,codefirst模式真的很麻烦,而且很容易出错,有些错误会让人感觉莫名其妙,同样的操作步骤,第一次还能成功,但第二次就会失败。这样的问题太多,导致

codefirst模式用起来不爽(也许是本人技术不行,没有吃透)。这三种模式,我觉得最好用的还是DBFirst,它首先要求在sqlserver中将数据库设计好,这与以前的数据库搭建没什么

区别,然后通过创建ado.net实体数据模型,选择从数据库生成的方式来创建实体,进而对数据库增删改查。如果对数据库有变更,那也是先在sqlserver中变更好了,再在实体模型中对变更的地方重新导入即可,整个过程稳定不会出现莫名其妙的错误。而modelfirst完全就是dbfirst的反操作。麻烦的地方就是如果需要变更数据库,首先得在实体模型中变更,完了后会产生一个sql文件,这个时候还不能执行这个sql文件,需要将不必要的sql语句屏蔽后才能执行。如果数据库没有数据或者表比较少的时候,还可以接受,否则每次对数据库有变更都需要手动的去sqlserver中更改,同时还得担心万一有人一不小心执行了sql文件,结果导致原来的数据全部丢失,那乐子就大了

 

posted @ 2017-03-21 14:12  你爱我像谁  阅读(759)  评论(0编辑  收藏  举报