我们知道无论是“Database First”还是“Model First”当模型发生改变了都可以通过Visual Studio设计视图进行更新,那么对于Code First如何更新已有的模型呢?今天我们简单介绍一下Entity Framework的数据迁移功能。

Entity Framework配置

在开始今天的话题之前先来看一下Entity Framework的配置,因为有很多朋友因为配置文件的问题造成“Migrations”命令执行失败。

在建立一个应用程序之后我们可以通过在项目上右键“Nuget Packages Manage”进行EF包安装或者直接在“Package Manager Console”中输入“Install-Package EntityFramework”命令进行Entity Framework包安装。这个过程不仅下载并引入了EF框架相关程序集还进行了包的配置和应用用程序配置。下面是这两个配置文件:

packages.config文件:

<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
</packages>

App.config文件:

<?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=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
</configuration>

packages.config内容比较简单,首先是EF自身版本,然后在安装过程中根据当前应用的.NET Framework版本配置了“targetFramework”,因为不同的.NET Framework版本对应的EF程序集不同,这在安装过程中会自动识别并配置。

App.config中自动添加了“entityFramework”配置节,在EF包安装过程中自动根据当前环境配置了“defaultConnectionFactory”, “defaultConnectionFactory”是EF默认的连接配置,只有在没有配置连接字符串时生效。在上一篇文章中我们提到如果不进行连接字符串配置EF会自动识别并创建数据库到“.\SQLEXPRESS”或者“LocalDb”,事实上就是通过这里识别的,可以看出我机器上没有“.\SQLEXPRESS”就自动使用了“LocalDb”,配置默认连接到“LocalDbConnectionFactory”。

在本例中我们需要将连接指向“.\SQL2008”上,有两种方式建立自己的连接:一种是直接配置“defaultConnectionFactory”,将默认生成的“System.Data.Entity.Infrastructure.LocalDbConnectionFactory”改成“System.Data.Entity.Infrastructure.SqlConnectionFactory”,然后在参数中编写我们的连接字符串(注意默认生成的数据库名为“项目名称.数据库上下文名称”)。

<?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=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=.\SQL2008; UID=sa;PWD=123; MultipleActiveResultSets=True" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
</configuration>

另一种是通过传统的 “connectionStrings” 配置,只要配置了连接字符串“defaultConnectionFactory”将不再生效,EF会自动使用该连接。在接下来的示例中我们将采用这种方式。

<?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=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="CodeFirstDb" connectionString="Data Source=.\SQL2008;Database=CodeFirstDb;UID=sa;PWD=123;MultipleActiveResultSets=true" providerName="System.Data.SqlClient"></add>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
</configuration>

Code First数据库迁移

现在让我们在上一篇文章Entity Framework 5.0系列之EF概览中的“Code First”示例的基础上给Order添加一个”Employee”属性,然后运行,不出意外的话你将看到如下异常:

从异常信息我们可以看出,EF已经检测到模型发生了改变,建议我们使用”Code First Migrations”对模型进行更新。事实上EF就是依靠上一篇文章中提到的“dbo.__MigrationHistory”表对我们的模型进行判断的,因为这张表中存储了我们的模型结构(在Model列中),如果运行程序时你跟踪SQL Server会发现EF执行了如下SQL进行模型修改判断:

SELECT Count(*) FROM sys.databases WHERE [name]=N'CodeFirstDb'
go
SELECT TABLE_SCHEMA SchemaName, TABLE_NAME Name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'
go
SELECT Count(*) FROM sys.databases WHERE [name]=N'CodeFirstDb'
go
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[__MigrationHistory] AS [Extent1]
) AS [GroupBy1]
go
SELECT TOP (1)
[Project1].[C1] AS [C1],
[Project1].[MigrationId] AS [MigrationId],
[Project1].[Model] AS [Model]
FROM ( SELECT
[Extent1].[MigrationId] AS [MigrationId],
[Extent1].[Model] AS [Model],
1 AS [C1]
FROM [dbo].[__MigrationHistory] AS [Extent1]
) AS [Project1]
ORDER BY [Project1].[MigrationId] DESC
go

在开始Code First数据库迁移之前,我们先对上一节编写的OrderContext类进行修改添加默认构造函数,因为Code First Migrations将会使用数据库上下文的默认构造函数进行数据迁移操作(尽管没有默认构造函数所有的数据操作都能正常进行,但是对于数据迁移这是必须的),因此我们需要添加一个默认构造函数,并且该构造函数中必须传入我们的数据库连接名称(如果使用上面我们说的第一种数据库连接配置方式则可以不用传递该参数),否则将会把更新应用到EF默认数据库上。下面是我们的OrderContext:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity; namespace CodeFirst
{
public class OrderContext:DbContext
{
public OrderContext()
: base("CodeFirstDb")
{
} public DbSet<Order> Orders
{
get;
set;
} public DbSet<OrderDetail> OrderDetails
{
get;
set;
}
}
}

下面我们将借助于”Code First Magrations” 进行模型更新。

在Visual Studio中执行:Tools->Library Package Manager->Package Manager Console来打开包管理命令行:

在命令行中输入“Enable-Migrations -StartUpProjectName CodeFirst”然后回车(“CodeFirst”是你的项目名称,如果在“Package Manager Console”中选择了默认项目可以不设置“-StartUpProjectName”参数;如果多次执行此命令可以添加-Force参数):

注意:如果在运行“Enable-Migrations -StartUpProjectName CodeFirst”命令过程中收到如下错误,请尝试下面给出的方法:

Enable-Migrations : The term 'Enable-Migrations' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

1. 在Package Manager Console中执行命令:Import-Module F:\[7]CSharp\EntityFramework\CodeFirst\packages\EntityFramework.5.0.0\tools\EntityFramework.PS3.psd1(后面的路径按照你EF包的实际位置修改,这个问题是由于没有导入相应命令造成的)

2. 执行“Install-Package EntityFramework -IncludePrerelease”命令重新安装最新版EF(也可以通过-Version参数指定具体版本)。

3. 更新Nuget,具体更新步骤见Installing NuGet

4. 另外,命令执行过程中其他错误可以按照错误提示解决。

如果没有错误你的项目中将自动生成一个名为”Migrations“的文件夹,里面包含两个文件: Configuration.cs和201308211510117_InitialCreate.cs(201308211510117是时间戳)。

Configuration.cs:是迁移配置代码,一般我们不需要修改。

namespace CodeFirst.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq; internal sealed class Configuration : DbMigrationsConfiguration<CodeFirst.OrderContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
} protected override void Seed(CodeFirst.OrderContext context)
{
// This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
}

201308211510117_InitialCreate.cs:以代码的形式记录了本地数据库的表结构定义。

namespace CodeFirst.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Orders",
c => new
{
Id = c.Int(nullable: false, identity: true),
Customer = c.String(),
OrderDate = c.DateTime(nullable: false),
})
.PrimaryKey(t => t.Id); CreateTable(
"dbo.OrderDetails",
c => new
{
Id = c.Int(nullable: false, identity: true),
Product = c.String(),
UnitPrice = c.String(),
OrderId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Orders", t => t.OrderId, cascadeDelete: true)
.Index(t => t.OrderId); } public override void Down()
{
DropIndex("dbo.OrderDetails", new[] { "OrderId" });
DropForeignKey("dbo.OrderDetails", "OrderId", "dbo.Orders");
DropTable("dbo.OrderDetails");
DropTable("dbo.Orders");
}
}
}

现在在” Package Manager Console”中执行“Add-Migration AddEmployee”命令,该命令会自动比较模型和当前数据库中的表结构,然后执行“AddEmployee”添加一个”Employee”列,此时在”Migrations“文件夹会生成一个名为“201308240757094_AddEmployee.cs”的类(201308240757094是时间戳):

201308240757094_AddEmployee.cs内容如下:

namespace CodeFirst.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class AddEmployee : DbMigration
{
public override void Up()
{
AddColumn("dbo.Orders", "Employee", c => c.String());
} public override void Down()
{
DropColumn("dbo.Orders", "Employee");
}
}
}

从这个类中我们可以看出事实上是给“Order”添加了“Employee”列,当然我们也可以手动修改这个类。

接下来,在“Package Manager Console”中执行“Update-Database -StartUpProjectName CodeFirst –Verbose”命令(添加-Verbose参数可以查看到更新脚本),进行数据库结构更新:

此时查看数据库,发现“Order”表已经多了一列:

OK,今天我们的内容就先到此,关于如何根据数据库生成代码类及其更多内容我们在后面的文章中再一起探讨。

Entity Framework 5.0系列之Code First数据库迁移的更多相关文章

  1. Entity Framework 5.0系列之自动生成Code First代码

    在前面的文章中我们提到Entity Framework的"Code First"模式也同样可以基于现有数据库进行开发.今天就让我们一起看一下使用Entity Framework P ...

  2. 【转】Entity Framework 5.0系列之自动生成Code First代码

    在前面的文章中我们提到Entity Framework的“Code First”模式也同样可以基于现有数据库进行开发.今天就让我们一起看一下使用Entity Framework Power Tools ...

  3. (转)Entity Framework 5.0系列之自动生成Code First代码

    原文地址:http://www.cnblogs.com/kenshincui/archive/2013/08/29/3290527.html 在前面的文章中我们提到Entity Framework的“ ...

  4. Entity Framework 5.0系列之数据操作

    Entity Framework将概念模型中定义的实体和关系映射到数据源,利用实体框架可以将数据源返回的数据具体化为对象:跟踪对象所做的更改:并发处理:将对象更改传播到数据源等.今天我们就一起讨论如何 ...

  5. Entity Framework 5.0系列之EF概览

    概述 在开发面向数据的软件时我们常常为了解决业务问题实体.关系和逻辑构建模型而费尽心机,ORM的产生为我们提供了一种优雅的解决方案.ADO.NET Entity Framework是.NET开发中一种 ...

  6. Entity Framework 5.0系列之EF概览-三种编程方式

    概述 在开发面向数据的软件时我们常常为了解决业务问题实体.关系和逻辑构建模型而费尽心机,ORM的产生为我们提供了一种优雅的解决方案.ADO.NET Entity Framework是.NET开发中一种 ...

  7. Entity Framework 5.0系列之约定配置

    Code First之所以能够让开发人员以一种更加高效.灵活的方式进行数据操作有一个重要的原因在于它的约定配置.现在软件开发越来复杂,大家也都试图将软件设计的越来越灵活,很多内容我们都希望是可配置的, ...

  8. 【转】Entity Framework 5.0系列之约定配置

    Code First之所以能够让开发人员以一种更加高效.灵活的方式进行数据操作有一个重要的原因在于它的约定配置.现在软件开发越来复杂,大家也都试图将软件设计的越来越灵活,很多内容我们都希望是可配置的, ...

  9. 3.3 使用Code First数据库迁移

    当Entity Framework Code First的数据模型发生异动时,默认会引发一个System.InvalidOpertaionException异常.一种解决方法是在Global.asax ...

随机推荐

  1. Qt 程序访问 sqlite 权限错误

    在Linux桌面上开发应用,想要拥有root权限,可是又需要弹窗申请.所以尽量避免这种情况发生. 另外:gksu,pkexec可以提供gui的root权限索取功能. 因为db文件是安装的时候放到etc ...

  2. WPF Combobox样式

    <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}&qu ...

  3. OD使用教程5

    怎样恢复数据被改过的代码 点击m进入内存分布图 双击进入文件头 将过大的值一一修改为正常值 普通程序没有动态链接表所以值改为0 保存:首先记住地址 其次 选中差不多的长度,保存 正常的程序

  4. 《UML大战需求分析》阅读笔记4

    流程分析利器之二,状态机图. 状态机图也可以叫状态图,也是用来分析流程的,之前的活动图的主体是事件的行为,而状态机图主要描述的是事件的状态. 开始:实心圆点: 结束:点加环:(与活动图一样) 状态:圆 ...

  5. 使用hibernate可以优化的地方

    a.  在查询字符串中,应该总是使用jdbc的占位符?,或使用使用命名参数:,不要自查询中使用字符串值来代替非常量值. b.  Flush会影响性能,频繁刷新影响性能,尽量减少不必要的刷新. c.   ...

  6. MATLAB 画出三个通信小区cell边界示意图

    d=1000; %两个小区中心间距离的一半 rcell=2*d/sqrt(3); %小区半径 ncell=3; %小区个数 cellposition=zeros(ncell,2); %初始化小区中心位 ...

  7. 初学 Java Web 开发,请远离各种框架,从 Servlet 开发

    Web框架是开发者在使用某种语言编写Web应用服务端时关于架构的最佳实践.很多Web框架是从实际的Web项目抽取出来的,仅和Web的请求和响应处 理有关,形成一个基础,在开发别的应用项目的时候则可以从 ...

  8. [Linux] xargs

    xargs 命令可以将一个命令的输出,作为另一个命令的输入! 这里听来好像是管道的功能,之所以有xargs是因为有的命令不知吃管道,这时xargs就派上用场了! 具体的方法是:前一个命令的输出会使用空 ...

  9. 使用 AForge.NET 做视频采集

    AForge.NET 是基于C#设计的,在计算机视觉和人工智能方向拥有很强大功能的框架.btw... it's an open source framework. 附上官网地址: http://www ...

  10. jquery设置元素的readonly和disabled

    jquery设置元素的readonly和disabled Jquery的api中提供了对元素应用disabled和readonly属性的方法,在这里记录下.如下: $( '#line2Tr' ).cs ...