创建数据库
首先创建一个控制台项目,安装 EntityFrame 并在项目中添加实体类和上下文。其中 ConnStr 表示配置文件中连接字符串的名字,DbContext 根据 DbSet 属性的类型来创建数据表
internal class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Grade Grade { get; set; }
}
internal class Grade
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Student> Students { get; set; }
}
internal class MyDBContext : DbContext
{
public MyDBContext() : base("name=ConnStr")
{
}
public virtual DbSet<Grade> Grades { set; get; }
}
配置文件配置如下,其中 entityFramework 和 SqlClient 相关是安装 EntityFrame 时自动配好的,我们需要添加 connectionString 为 自己的数据库链接
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<entityFramework>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<connectionStrings>
<add name="ConnStr" connectionString="initial catalog=Test0424;data source=.;user id=sa;password=Aa123456" providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>
最后在 Main 方法中调用 DbSet 数据,启动程序就能看到在本地数据库中生成了 Grade 和Student 表,虽然我们没有为 DbContext 添加 Student 类型的 DbSet ,但依然创建了 Student 表,这是因为在 Grade 中定义了关联属性 Students
static void Main(string[] args)
{
using(MyDBContext context = new MyDBContext())
{
Grade grade = context.Grades.FirstOrDefault();
}
}
如果运行过程中报以下的错误,说明在实体类中没有设置 主键 ,EntityFramework会默认把属性名为 Id 的属性设置为主键,如果要指定别的字段为主键需要使用特性 [Key] ,需要注意的是应该定义为属性而不是字段
"EntityType 'Grade' has no key defined. Define the key for this EntityType.Grade: EntityType: EntitySet 'Grade' is based on type 'Grade' that has no keys defined."
修改数据库
现在给 Student 类添加 Age 字段
internal class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public virtual Grade Grade { get; set; }
}
再次运行 Main 方法,报以下的错误,说明实体类在创建后已经被修改了,需要对数据库进行更新
“The model backing the 'MyDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).”
1、首先打开 程序包管理控制台
2、输入 Enable-Migrations ,得到以下输出结果并发现在项目下多了一个 Migrations 文件夹,输出结果的大概意思就是如果要使用 自动迁移 ,需要删除 Migrations文件夹 并重新运行Enable-Migrations,并指定 EnableAutomaticMigrations 参数。在启用自动迁移之后,我们再修改实体文件,只需执行 Update-Database 命令即可完成对数据库的更新
InitialCreate文件:因为我们事先让 Code First 自动创建了一个数据库,这个迁移文件中的代码表示数据库中已创建的对象。文件名包含时间戳,如果尚未创建数据库,则不会将此 InitialCreate 迁移添加到项目中,在调用 Add-Migration 时,InitialCreate 文件创建表的代码将为新迁移搭建基架
Configuration文件 :我们可以在此文件中针对上下文配置迁移行为
3、启用迁移之后,继续输入 Update-Database 命令来更新数据库
通过上面的提示信息我们可以知道,要想更新数据库需要启用 自动迁移 或者使用 Add-Migration命令来创建迁移文件
4、在控制台输入 Add-Migration MigrationName ,运行得到以下输出结果并发现在 Migrations 文件夹中多了一个时间戳加迁移名称的文件
5、打开 MigrationName 文件,得到以下代码。在迁移文件中描述了迁移需要进行的操作,因此我们也可以直接修改迁移文件而不用修改实体类
public partial class MigrationName : DbMigration
{
/// <summary>
/// 这是一个覆盖方法,表示迁移的“上升”操作,即在数据库中应用迁移时要执行的操作
/// </summary>
public override void Up()
{
//AddColumn方法用于向名为“Students”的数据库表中添加一个名为“Age”的列,其数据类型为整数,并且指定该列不允许为空。
//"dbo.Students"表示数据库中的表,"Age"表示要添加的列名,c => c.Int(nullable: false)表示列的数据类型为整数且不允许为空
AddColumn("dbo.Students", "Age", c => c.Int(nullable: false));
}
/// <summary>
/// 这是另一个覆盖方法,表示迁移的“下降”操作,即在需要撤销迁移时要执行的操作
/// </summary>
public override void Down()
{
//DropColumn方法用于从名为“Students”的数据库表中删除名为“Age”的列。"dbo.Students"表示数据库中的表,"Age"表示要删除的列名
DropColumn("dbo.Students", "Age");
}
}
6、最后在程序包管理器控制台输入 Update-Database ,也可以使用 Update-Database -Verbose 命令,该命令可以使我们看到SQL语句的执行过程,得到以下输出结果,并且刷新数据库发现修改已经迁移进来