Entity Framework 5.0系列之Code First数据库迁移

简介:

我们知道无论是“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,今天我们的内容就先到此,关于如何根据数据库生成代码类及其更多内容我们在后面的文章中再一起探讨。

目录
相关文章
|
7天前
|
弹性计算 关系型数据库 数据库
自建数据库迁移到云数据库实操
本课程详细介绍了自建数据库迁移到阿里云RDS的实操步骤。主要内容包括:创建实例资源、安全设置、配置自建的MySQL数据库、数据库的迁移、从自建数据库切换到RDS以及清理资源。通过这些步骤,学员可以掌握如何将自建数据库安全、高效地迁移到云端,并确保应用的正常运行。
67 26
|
23天前
|
弹性计算 安全 关系型数据库
活动实践 | 自建数据库迁移到云数据库
通过阿里云RDS,用户可获得稳定、安全的企业级数据库服务,无需担心数据库管理与维护。该方案使用RDS确保数据库的可靠性、可用性和安全性,结合ECS和DTS服务,实现自建数据库平滑迁移到云端,支持WordPress等应用的快速部署与运行。通过一键部署模板,用户能迅速搭建ECS和RDS实例,完成数据迁移及应用上线,显著提升业务灵活性和效率。
|
7天前
|
运维 关系型数据库 MySQL
自建数据库迁移到云数据库RDS
本次课程由阿里云数据库团队的凡珂分享,主题为自建数据库迁移至云数据库RDS MySQL版。课程分为四部分:1) 传统数据库部署方案及痛点;2) 选择云数据库RDS MySQL的原因;3) 数据库迁移方案和产品选型;4) 线上活动与权益。通过对比自建数据库的局限性,介绍了RDS MySQL在可靠性、安全性、性价比等方面的优势,并详细讲解了使用DTS(数据传输服务)进行平滑迁移的步骤。此外,还提供了多种优惠活动信息,帮助用户降低成本并享受云数据库带来的便利。
|
22天前
|
安全 关系型数据库 MySQL
体验自建数据库迁移到云数据库RDS,领取桌面置物架!
「技术解决方案【Cloud Up 挑战赛】」正式开启!本方案旨在帮助用户将自建数据库平滑迁移至阿里云RDS MySQL,享受稳定、高效、安全的数据库服务,助力业务快速发展。完成指定任务即可赢取桌面置物架等奖励,限量供应,先到先得。活动时间:2024年12月3日至12月31日16点。
|
2月前
|
算法 大数据 数据库
云计算与大数据平台的数据库迁移与同步
本文详细介绍了云计算与大数据平台的数据库迁移与同步的核心概念、算法原理、具体操作步骤、数学模型公式、代码实例及未来发展趋势与挑战。涵盖全量与增量迁移、一致性与异步复制等内容,旨在帮助读者全面了解并应对相关技术挑战。
57 3
|
3月前
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
529 15
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
3月前
|
SQL Java 数据库连接
数据库迁移不再难:Flyway 与 Liquibase 大比拼,哪个才是你的真命天子?
【9月更文挑战第3天】数据库迁移在软件开发中至关重要,尤其在使用 ORM 框架如 Hibernate 时。为确保部署时能顺利应用最新的数据库变更,开发者常使用自动化工具。Flyway 和 Liquibase 是当前流行的两种选择,均能有效管理数据库版本控制。Flyway 采用 SQL 脚本表示变更,简单易用;Liquibase 支持多种脚本格式,功能更强大,适合复杂项目。本文将对比这两种工具的特点,并通过示例展示各自的优缺点,帮助开发者根据项目需求做出合适的选择。
806 1
|
4天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
17 3
|
4天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
21 3
|
4天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE &#39;log_%&#39;;`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
26 2