威尼斯人线上娱乐

高等编制程序,全自动迁移数据库的得以落成

22 4月 , 2019  

在付出涉及到数据库的次第时,常会碰着一齐首布置的结构不可能满足需要要求再增加新字段或新表的景况,那时就须要开始展览数据库迁移。
兑现数据库迁移有很七种措施,从手动管理种种版本的ddl脚本,到贯彻和睦的migrator,或是使用Entity
Framework提供的Code First迁移功用。
Entity
Framework提供的迁移成效能够满足大多数人的须要,但仍会存在难以分等级次序管理迁移代码和轻松并发”context
has changed”错误的难点。

在支付涉及到数据库的先后时,常会境遇一齐头陈设的构造无法满意急需须求再增加新字段或新表的情景,那时就需求进行数据库迁移。
兑现数据库迁移有很八种艺术,从手动管理各样版本的ddl脚本,到得以落成协和的migrator,或是使用Entity
Framework提供的Code First迁移作用。
Entity
Framework提供的迁移作用能够满意半数以上人的要求,但仍会设有难以分品种管理迁移代码和易于出现”context
has changed”错误的标题。

**译文,个体原创,转发请阐明出处(C# 陆 与 .NET Core 一.0 高等编制程序 – 38 章 实体框架宗旨(上)),不对的地点接待提议与沟通。** 

章节出自《Professional
C# 6 and .NET Core
壹.0》。水平有限,各位阅读时精心甄别,唯望莫误人子弟。

附英文版原作:Professional C# 6 and .NET Core 1.0 – 38 Entity
Framework
Core

本章节译文分为上下篇,下篇见: C# 六 与 .NET Core 一.0 高端编制程序 – 3八 章
实体框架大旨(下)


本章内容

  • Entity
    Framework Core 1.0简介
  • 使用信赖注入实体框架
  • 始建关系模型
  • 使用.NET
    CLI工具和MSBuild实行搬迁
  • 目的追踪
  • 更新目的和目的树
  • 争论管理与创新
  • 利用专业

Wrox.Com关于本章的源代码下载

本章的wrox.com代码下载位于
www.wrox.com/go/professionalcsharp陆下载代码选项卡。本章的代码首要有以下示例:

  • Books
    Sample
  • Books
    Sample with DI
  • Menus
    Sample
  • Menus
    with Data Annotations
  • Conflict
    Handling Sample
  • Transactions
    Sample 

**译文,民用原创,转发请注解出处(C# 陆 与 .NET Core 一.0 高等编程 – 3八 章 实体框架焦点(上)),不对的地点迎接指出与交流。** 

章节出自《Professional
C# 陆 and .NET Core
1.0》。水平有限,各位阅读时仔细辨认,唯望莫误人子弟。

附英文版原来的小说:Professional C# 6 and .NET Core 1.0 – 38 Entity
Framework
Core

本章节译文分为上下篇,下篇见: C# 6 与 .NET Core 1.0 高档编制程序 – 3八 章
实体框架主题(下)


本章内容

  • Entity
    Framework Core 1.0简介
  • 应用信赖注入实体框架
  • 创设关系模型
  • 使用.NET
    CLI工具和MSBuild进行搬迁
  • 对象追踪
  • 履新目的和对象树
  • 争辩管理与更新
  • 运用工作

Wrox.Com关于本章的源代码下载

本章的wrox.com代码下载位于
www.wrox.com/go/professionalcsharp6下载代码选项卡。本章的代码首要有以下示例:

  • Books
    Sample
  • Books
    Sample with DI
  • Menus
    Sample
  • Menus
    with Data Annotations
  • Conflict
    Handling Sample
  • Transactions
    Sample 

此处我将介绍ZKWeb网页框架在Fluent
NHibernate和Entity Framework Core上运用的章程。
能够产生增添实体字段后,只需刷新网页就足以把退换应用到数据库。

此处笔者将介绍ZKWeb网页框架在Fluent
NHibernate和Entity Framework Core上使用的秘籍。
能够做到增多实体字段后,只需刷新网页就能够把改变应用到数据库。

实业框架的野史

实体框架是提供实体到事关的映照的框架。通过那种办法,能够创制映射到数码库表的项目,使用LINQ创制数据库查询,创制和更新目的,并将它们写入数据库。 

由此多年对Entity
Framework的微量修改,最新的本子是三个通通的重写。一同来看望Entity
Framework的历史,以及重写的原由。

  • Entity
    Framework 1
    —Entity Framework的率先个版本未有桑土计划好与.NET
    3.五合作,但它高效就足以与.NET 叁.五 SP一包容。另一个产品LINQ to
    SQL提供了某个像样的效应,且早已可用于.NET 3.五。 LINQ to SQL和Entity
    Framework在非常大程度上提供了接近的效益。LINQ to
    SQL更便于使用,但不得不用来访问SQL
    Server。实体框架是依据提供程序的,并提供了对两样关周详据库的拜访。它含有越多的机能,举个例子多对多映射而不需求映射对象,n对n映射是唯恐的。
    Entity
    Framework的八个欠缺是它的模型类型须求由EntityObject基类派生。将对象映射到事关选择含有XML的EDMX文件完成的。包涵的XML由七个格局组成:概念格局定义(CSD)定义具有其本性和关系的靶子类型;存储情势定义(SSD)定义数据库表、列和涉嫌;以及映射格局语言(MSL)定义CSD和SSD怎样相互映射。

  • Entity
    Framework 4
    —Entity Framework 四 在.NET
    四中卓殊,并且获得了关键创新,个中大多源点LINQ到SQL的主张。由于变化十分的大,版本二和3已被跳过。这几个版本里扩充了延期加载以赢得访问属性的关联。在行使SQL数据定义语言(DDL)设计模型之后,能够创立数据库。今后使用Entity
    Framework的多个模型是Database First或Model
    First。恐怕最重要的特征是帮忙轻易对象类(POCO),因而不再要求从基类EntityObject派生。

乘势更新(举例Entity
Framework 四.1,4.二),NuGet包扩充了额外的功能,因而能更加快地丰裕效果。
Entity Framework 4.一提供了Code
First模型,其中用于定义映射的EDMX文件不再动用。相反,全体的炫酷都采用C#代码定义

  • 动用性质或Fluent API来定义的映照。

Entity Framework
四.3增添了对搬迁的协理。有了那或多或少,就足以接纳C#代码定义数据库结构的更动。使用数据库从应用程序自动应用数据库更新。

  • Entity
    Framework 5
    —Entity Framework 5的NuGet包帮助.NET 4.5和.NET
    肆应用程序。但是,Entity Framework 5的不少效果都可用于.NET 4.伍。
    Entity Framework依然基于.NET
    四.五在系统上设置的种类。此版本的新增加效益是性质立异以及协助新的SQL
    Server作用,比如空间数据类型。

  • Entity
    Framework 6
    —Entity Framework 6解决了Entity Framework
    伍的局地难点,在那之中有个别是设置在系统上的框架的一有的,壹部分经过NuGet扩充提供。近期Entity
    Framework的万事代码已移至NuGet包。为了不形成冲突,使用了三个新的命名空间。将应用程序移植到新本未时,必须改换命名空间。

威尼斯人线上娱乐 ,本书探究Entity
Framework的新型版本,Entity Framework Core
一.0。此版本是三个删减旧的一坐一起周全重写,不再支持CSDL,SSDL和MSL的XML文件映射,只辅助Code
First – 使用Entity Framework 四.一增加的模型。Code First
并不代表数据库不能够先存在。您能够先创建数据库,可能仅从代码中定义数据库,以上二种采取都以立竿见影的。

注意 Code First
这么些称谓某个程度上令人误会。Code First
先创立代码或先数据库都是卓有成效的。最初Code First的测试版本名称是Code
Only。因为其余模型选项在称呼和浩特中学有First,所以“Code
Only”的名目也被改成。

Entity
Framework 的周全重写不仅扶助关周全据库,还匡助NoSql数据库 –
只须求3个提供程序。在编写本文时,提供程序扶助少数,但相信会随时间而充实。 

新本子的Entity
Framework基于.NET
Core,由此在Linux和Mac系统上也得以应用此框架。 

Entity
Framework Core 一.0不完全援救Entity Framework
6提供的持有机能。随着岁月的推迟,Entity
Framework的新本子将提供越来越多职能,留意所选拔的Entity
Framework的本子。就算选取Entity Framework 陆繁多有力的理由,但在非Windows平台上选拔ASP.NET Core 壹.0、Entity
Framework和通用Windows平台(UWP),以及非关全面据存款和储蓄,都需求使用Entity
Framework Core 一.0。 

本章介绍Entity
Framework Core 一.0。从一个总结的模型读取和SQL
Server中写入音讯初阶,稍后会介绍增多关系,在写入数据库时将介绍改动追踪器和争执管理。利用搬迁创设和修改数据库结构是本章的另二个珍视部分。 

注意 本章使用Books数据库,此数据库包蕴在示范代码的下载包中 www.wrox.com/go/professionalcsharp6. 

实体框架的历史

实业框架是提供实体到关系的映射的框架。通过这种办法,能够创制映射到数码库表的花色,使用LINQ创设数据库查询,创立和换代目的,并将它们写入数据库。 

由此长年累月对Entity
Framework的少许改造,最新的版本是3个通通的重写。一同来看望Entity
Framework的野史,以及重写的缘由。

  • 高等编制程序,全自动迁移数据库的得以落成。Entity
    Framework 1
    —Entity Framework的首先个版本未有有备无患好与.NET
    三.5相称,但它高效就足以与.NET 3.伍 SP一包容。另1个产品LINQ to
    SQL提供了有的近似的作用,且早已可用于.NET 3.5。 LINQ to SQL和Entity
    Framework在非常的大程度上提供了接近的服从。LINQ to
    SQL更易于使用,但不得不用来访问SQL
    Server。实体框架是依照提供程序的,并提供了对分歧关周全据库的拜访。它包蕴更加多的效应,举个例子多对多映射而不需求映射对象,n对n映射是或许的。
    Entity
    Framework的3个通病是它的模子类型必要由EntityObject基类派生。将对象映射到关系选用含有XML的EDMX文件完结的。包蕴的XML由八个格局组成:概念情势定义(CSD)定义具有其天性和涉嫌的靶子类型;存款和储蓄格局定义(SSD)定义数据库表、列和事关;以及映射格局语言(MSL)定义CSD和SSD如何互相映射。

  • Entity
    Framework 4
    —Entity Framework 四 在.NET
    四中万分,并且获得了不可或缺改良,在那之中多数源点LINQ到SQL的主见。由于变化比较大,版本贰和三已被跳过。这一个版本里扩大了推迟加载以获取访问属性的关联。在应用SQL数据定义语言(DDL)设计模型之后,可以创建数据库。未来应用Entity
    Framework的五个模型是Database First或Model
    First。可能最重视的天性是支持轻巧对象类(POCO),由此不再须求从基类EntityObject派生。

随着更新(比方Entity
Framework 四.一,肆.2),NuGet包扩充了额外的效益,由此能越来越快地充足效果。
Entity Framework 4.1提供了Code
First模型,当中用于定义映射的EDMX文件不再动用。相反,全体的炫耀都选拔C#代码定义

  • 利用性质或Fluent API来定义的映照。

Entity Framework
4.三扩张了对搬迁的帮忙。有了那或多或少,就足以接纳C#代码定义数据库结构的退换。使用数据库从应用程序自动应用数据库更新。

  • Entity
    Framework 5
    —Entity Framework 伍的NuGet包支持.NET 四.五和.NET
    4应用程序。不过,Entity Framework 5的大队人马效应都可用于.NET 四.5。
    Entity Framework照旧基于.NET
    四.五在系统上设置的类型。此版本的新添效益是性质革新以及帮忙新的SQL
    Server成效,举例空间数据类型。

  • Entity
    Framework 6
    —Entity Framework 六消除了Entity Framework
    5的一些难点,个中有的是设置在系统上的框架的一局部,一部分经过NuGet扩张提供。近来Entity
    Framework的上上下下代码已移至NuGet包。为了不形成争辨,使用了三个新的命名空间。将应用程序移植到新本辰时,必须更换命名空间。

本书商讨Entity
Framework的新星版本,Entity Framework Core
一.0。此版本是二个删减旧的行为周详重写,不再帮衬CSDL,SSDL和MSL的XML文件映射,只援助Code
First – 使用Entity Framework 四.壹加上的模型。Code First
并不代表数据库不能够先存在。您能够先创造数据库,可能仅从代码中定义数据库,以上二种选拔都是实惠的。

注意 Code First
那几个名称有些程度上令人误解。Code First
先创设代码或先数据库都是行得通的。最初Code First的测试版本名称是Code
Only。因为其余模型选项在称呼和浩特中学有First,所以“Code
Only”的名号也被更换。

Entity
Framework 的完美重写不仅援助关周详据库,还帮衬NoSql数据库 –
只必要三个提供程序。在写作本文时,提供程序辅助有限,但相信会随时间而充实。 

新本子的Entity
Framework基于.NET
Core,由此在Linux和Mac系统上也得以动用此框架。 

Entity
Framework Core 一.0不完全辅助Entity Framework
陆提供的有所效率。随着时间的推迟,Entity
Framework的新本子将提供越来越多效益,留意所运用的Entity
Framework的版本。纵然选择Entity Framework 6许多强硬的说辞,但在非Windows平台上应用ASP.NET Core 1.0、Entity
Framework和通用Windows平台(UWP),以及非关全面据存款和储蓄,都亟需利用Entity
Framework Core 壹.0。 

本章介绍Entity
Framework Core 一.0。从三个简易的模子读取和SQL
Server中写入新闻开端,稍后会介绍增多关系,在写入数据库时将介绍改变追踪器和争持管理。利用搬迁创建和修改数据库结构是本章的另叁个重中之重片段。 

注意 本章使用Books数据库,此数据库包括在示范代码的下载包中 www.wrox.com/go/professionalcsharp6. 

贯彻机关迁移的笔触

数据库迁移须要钦定退换的局地,比如增多表和增多字段。
而落成活动员搬迁移供给自动生成那一个改造的一些,具体来讲供给

  • 获得数据库现成的构造
  • 赢得代码中存活的布局
  • 比较之下结构之间的反差并扭转迁移

那多亏Entity Framework的Add-Migration(或dotnet ef migrations
add)命令所做的专业,
接下去大家将看哪样不使用那类的通令,在NHibernate, Entity
Framework和Entity Framework Core中贯彻机关的管理。

兑现自动员搬迁移的思绪

数据库迁移须要钦定更改的有的,举例增加表和丰裕字段。
而落实机关迁移必要自动生成这些退换的1对,具体来说须要

  • 取得数据库现存的结构
  • 得到代码中幸存的协会
  • 绝对来讲结构之间的歧异并生成迁移

那正是Entity Framework的Add-Migration(或dotnet ef migrations
add)命令所做的业务,
接下去大家将看怎么不采纳那类的一声令下,在NHibernate, Entity
Framework和Entity Framework Core中达成机关的处理。

实业框架简要介绍

第3个示范使用单个Book类型,并将此类型映射到SQL
Server数据库中的Books表。能够将记录写入数据库,然后读取,更新和删除它们。 

在首先个示范中,首先成立数据库。能够应用Visual
Studio 二〇一五中的SQL
Server对象财富管理器推行此操作。选取数据库实例(与Visual
Studio一同安装的(localdb)\
MSSQLLocalDB),单击树视图中的数据库节点,然后选取“增添新数据库”。示例数据库只有多少个名称叫Books的表。 

挑选Books数据库中的表节点,然后选用”增加新表”来创制表Books。使用图3八.第11中学所示的设计器,也许通过在T-SQL编辑器中输入SQL
DDL语句,都能够创建表Books。以下代码段显示了用来创制表的T-SQL代码。单击“更新”开关可以将改成提交到数据库。

CREATE TABLE [dbo].[Books]
(
  [BookId] INT NOT NULL PRIMARY KEY IDENTITY,
  [Title] NVARCHAR(50) NOT NULL,
  [Publisher] NVARCHAR(25) NOT NULL
)

实业框架简要介绍

第三个示范使用单个Book类型,并将此类型映射到SQL
Server数据库中的Books表。能够将记录写入数据库,然后读取,更新和删除它们。 

在率先个示范中,首先成立数据库。能够行使Visual
Studio 2014中的SQL
Server对象财富处理器实施此操作。采用数据库实例(与Visual
Studio一齐安装的(localdb)\
MSSQLLocalDB),单击树视图中的数据库节点,然后选用“增多新数据库”。示例数据库唯有一个名称叫Books的表。 

慎选Books数据库中的表节点,然后选择”加多新表”来创立表Books。使用图3八.第11中学所示的设计器,只怕通过在T-SQL编辑器中输入SQL
DDL语句,都得以创建表Books。以下代码段展现了用于创造表的T-SQL代码。单击“更新”开关能够将改变提交到数据库。

CREATE TABLE [dbo].[Books]
(
  [BookId] INT NOT NULL PRIMARY KEY IDENTITY,
  [Title] NVARCHAR(50) NOT NULL,
  [Publisher] NVARCHAR(25) NOT NULL
)

Fluent NHibernate的自动员搬迁移

ZKWeb框架使用的欧洲经济共同体代码能够查阅那里

首先Fluent
NHibernate供给丰盛全部实体的照射类型,以下是生成配置和丰硕实业映射类型的例证。
配置类的组织能够翻看那里

var db = MsSqlConfiguration.MsSql2008.ConnectionString("连接字符串");
var configuration = Fluently.Configure();
configuration.Database(db);
configuration.Mappings(m => {
    m.FluentMappings.Add(typeof(FooEntityMap));
    m.FluentMappings.Add(typeof(BarEntityMap));
    ...
});

接下去是把具备实体的组织丰富或更新到数据库。
NHibernate提供了SchemaUpdate,那一个类能够自动质量评定数据库中是或不是曾经有表或字段,未有时自动抬高。
运用格局十三分简单,以下是选择的事例

configuration.ExposeConfiguration(c => {
    // 第一个参数 false: 不把语句输出到控制台
    // 第二个参数 true: 实际在数据库中执行语句
    new SchemaUpdate(c).Execute(false, true);
});

到这一步就已经达成了全自动员搬迁移,但大家还有创新的余地。
因为SchemaUpdate不保留景况,每一回都要检验数据库中的整个结构,所以举行起来EF的迁徙要缓慢多数,
ZKWeb框架为了裁减每便运转网址的时辰,在实践更新以前还会检查实验是还是不是需求创新。

var scriptBuilder = new StringBuilder();
scriptBuilder.AppendLine("/* this file is for database migration checking, don't execute it */");
new SchemaExport(c).Create(s => scriptBuilder.AppendLine(s), false);
var script = scriptBuilder.ToString();
if (!File.Exists(ddlPath) || script != File.ReadAllText(ddlPath)) {
    new SchemaUpdate(c).Execute(false, true);
    onBuildFactorySuccess = () => File.WriteAllText(ddlPath, script);
}

这段代码应用了SchemaExport来扭转全体表的DDL脚本,生成后和上次的浮动结果相比,分歧时才调用SchemaUpdate更新。

NHibernate提供的机关迁移有以下的表征,使用时应有专注

  • 字段只会增添,不会去除,假若您重命名了字段原来的字段也会保留在数据库中
  • 字段类型借使改造,数据库不会跟着变动
  • 提到的外键借使改变,迁移时有比十分的大也许会出错

小结NHibernate的机动员搬迁移只会增加表和字段,基本不会修改原有的协会,有必然的限制只是正如安全。

Fluent NHibernate的全自动迁移

ZKWeb框架使用的总体代码能够查看那里

首先Fluent
NHibernate须要加多全体实体的映射类型,以下是调换配置和增进实业映射类型的例子。
配置类的结构能够查看那里

var db = MsSqlConfiguration.MsSql2008.ConnectionString("连接字符串");
var configuration = Fluently.Configure();
configuration.Database(db);
configuration.Mappings(m => {
    m.FluentMappings.Add(typeof(FooEntityMap));
    m.FluentMappings.Add(typeof(BarEntityMap));
    ...
});

接下去是把具备实体的结构丰裕或更新到数据库。
NHibernate提供了SchemaUpdate,那么些类能够自动质量评定数据库中是不是早已有表或字段,未有时自动抬高。
利用办法卓殊轻易,以下是利用的例证

configuration.ExposeConfiguration(c => {
    // 第一个参数 false: 不把语句输出到控制台
    // 第二个参数 true: 实际在数据库中执行语句
    new SchemaUpdate(c).Execute(false, true);
});

到这一步就早已达成了自行迁移,但大家还有创新的后路。
因为SchemaUpdate不保留处境,每便都要检查测试数据库中的整个结构,所以进行起来EF的动员搬迁要舒缓多数,
ZKWeb框架为了减小每一回运行网站的年华,在实践更新从前还会检验是不是需求更新。

var scriptBuilder = new StringBuilder();
scriptBuilder.AppendLine("/* this file is for database migration checking, don't execute it */");
new SchemaExport(c).Create(s => scriptBuilder.AppendLine(s), false);
var script = scriptBuilder.ToString();
if (!File.Exists(ddlPath) || script != File.ReadAllText(ddlPath)) {
    new SchemaUpdate(c).Execute(false, true);
    onBuildFactorySuccess = () => File.WriteAllText(ddlPath, script);
}

那段代码应用了SchemaExport来扭转全数表的DDL脚本,生成后和上次的转换结果比较,不平等时才调用SchemaUpdate更新。

NHibernate提供的机动员搬迁移有以下的风味,使用时应当小心

  • 字段只会助长,不会去除,假使您重命名了字段原来的字段也会保留在数据库中
  • 字段类型假使退换,数据库不会随之变动
  • 波及的外键假若改变,迁移时有望会出错

小结NHibernate的自发性迁移只会增多表和字段,基本不会修改原有的结构,有自然的限定只是正如安全。

成立模型 

用以访问Books数据库的言传身教应用程序BookSample是贰个调控台应用程序(Package)。此示例使用以下正视项和命名空间:

  依赖项

NETStandard.Library
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer

   取名空间

Microsoft.EntityFrameworkCore
System.ComponentModel.DataAnnotations.Schema
System
System.Linq
System.Threading.Tasks
static System.Console

 威尼斯人线上娱乐 1


38.1
  

Book类是二个轻便易行的实业类型,它定义了两性格情。
BookId属性映射到表的主键,Title属性指向标题列,Publisher属性指向Publisher列。Table属性应用于类型将品种映射到Books表(代码文件Books萨姆ple
/ Book.cs):

[Table("Books")]
public class Book
{
  public int BookId { get; set; }
  public string Title { get; set; }
  public string Publisher { get; set; }
}

开创模型 

用于访问Books数据库的以身作则应用程序BookSample是2个调控台应用程序(Package)。此示例使用以下重视项和命名空间:

  依赖项

NETStandard.Library
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer

   取名空间

Microsoft.EntityFrameworkCore
System.ComponentModel.DataAnnotations.Schema
System
System.Linq
System.Threading.Tasks
static System.Console

 威尼斯人线上娱乐 2


38.1
  

Book类是2个简便的实体类型,它定义了七个属性。
BookId属性映射到表的主键,Title属性指向标题列,Publisher属性指向Publisher列。Table属性应用于类型将品种映射到Books表(代码文件BooksSample
/ Book.cs):

[Table("Books")]
public class Book
{
  public int BookId { get; set; }
  public string Title { get; set; }
  public string Publisher { get; set; }
}

Entity Framework的电动迁移

ZKWeb框架没有帮助Entity Framework 6,但贯彻相比较简单笔者就径直上代码了。
例子

// 调用静态函数,放到程序启动时即可
// Database是System.Data.Entity.Database
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyConfiguration>());

public class MyConfiguration : DbMigrationsConfiguration<MyContext> {
    public MyConfiguration() {
        AutomaticMigrationsEnabled = true; // 启用自动迁移功能
        AutomaticMigrationDataLossAllowed = true; // 允许自动删字段,危险但是不加这个不能重命名字段
    }
}

Entity Framework提供的自动员搬迁移有以下的性情,使用时应有专注

  • 如果字段重命名,旧的字段会被删除掉,推荐做好数据的备份和尽量防止重命名字段
  • 外键关联和字段类型都会自动生成,变化时有十分大也许会招致原有的多少丢失
  • 机关迁移的记录和平运动用工具迁移同样,都会保存在__MigrationHistory表中,切勿混用不然代码将不能够用到新的数据库中

小结Entity
Framework的动员搬迁能够确认保证实体和数据库之间很强的壹致性,可是使用不当会导致原本数据的丢失,请务必做好数据库的按期备份。

Entity Framework的自动员搬迁移

ZKWeb框架未有帮忙Entity Framework 陆,但贯彻比较简单小编就径直上代码了。
例子

// 调用静态函数,放到程序启动时即可
// Database是System.Data.Entity.Database
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyConfiguration>());

public class MyConfiguration : DbMigrationsConfiguration<MyContext> {
    public MyConfiguration() {
        AutomaticMigrationsEnabled = true; // 启用自动迁移功能
        AutomaticMigrationDataLossAllowed = true; // 允许自动删字段,危险但是不加这个不能重命名字段
    }
}

Entity Framework提供的全自动员搬迁移有以下的风味,使用时应有专注

  • 若果字段重命名,旧的字段会被去除掉,推荐做好数据的备份和尽量防止重命名字段
  • 外键关联和字段类型都会自动生成,变化时有异常的大希望会促成原有的数据丢失
  • 机关迁移的笔录和利用工具迁移一样,都会保存在__MigrationHistory表中,切勿混用不然代码将不能够用到新的数据库中

总括Entity
Framework的迁徙能够确认保证实体和数据库之间很强的壹致性,但是使用不当会促成原本数据的不见,请务必做好数据库的定期备份。

始建上下文 

创办的BooksContext类实现Book表与数据库的关系。这一个类派生自基类DbContext,BooksContext类定义Books属性类型为DbSet
<Book>。此类型允许创制查询并增添Book实例以将其积累在数据库中。要定义连接字符串,能够重写DbContext的OnConfiguring方法。UseSqlServer扩大方法将左右文映射到SQL
Server数据库(代码文件BooksSample / BooksContext.cs):

public class BooksContext: DbContext
{
  private const string ConnectionString =  @"server= (localdb)\MSSQLLocalDb;database=Books;trusted_connection=true";
  public DbSet<Book> Books { get; set; }
  protected override void OnConfiguring(DbContextOptionsBuilder  optionsBuilder)
  {
    base.OnConfiguring(optionsBuilder);
    optionsBuilder.UseSqlServer(ConnectionString);
  }
}

概念连接字符串的另1个抉择是选取重视注入,将要本章后边介绍。 

开创上下文 

始建的BooksContext类完毕Book表与数据库的关系。那几个类派生自基类DbContext,BooksContext类定义Books属性类型为DbSet
<Book>。此类型允许成立查询并增加Book实例以将其积攒在数据库中。要定义连接字符串,可以重写DbContext的OnConfiguring方法。UseSqlServer扩充方法将左右文映射到SQL
Server数据库(代码文件Books萨姆ple / BooksContext.cs):

public class BooksContext: DbContext
{
  private const string ConnectionString =  @"server= (localdb)\MSSQLLocalDb;database=Books;trusted_connection=true";
  public DbSet<Book> Books { get; set; }
  protected override void OnConfiguring(DbContextOptionsBuilder  optionsBuilder)
  {
    base.OnConfiguring(optionsBuilder);
    optionsBuilder.UseSqlServer(ConnectionString);
  }
}

概念连接字符串的另贰个抉择是应用注重注入,就要本章前边介绍。 

Entity Framework Core的全自动员搬迁移

Entity Framework
Core去掉了SetInitializer采纳,代替他的是DatabaseFacade.MigrateDatabaseFacade.EnsureCreated
DatabaseFacade.Migrate能够利用使用ef命令生成的动员搬迁代码,防止在生养处境中实行ef命令。
DatabaseFacade.EnsureCreated则始于成立全数数据表和字段,但不得不创建不可能更新,不会加多纪录到__MigrationHistory
那四个函数都不能够促成全自动员搬迁移,ZKWeb框架使用了EF内部提供的函数,完整代码能够翻看这里

Entity Framework Core的机动员搬迁移实现比较复杂,我们须要分两步走。

  • 先是步
    创设迁移记录__ZKWeb_MigrationHistory表,那几个表和EF自带的布局同样,但以此表是给自个儿用的不是给ef命令用的
  • 其次部
    查找最终一条迁移记录,和当前的结构进行比较,寻觅差距并立异数据库

先是步的代码应用了EnsureCreated创制数据库和迁移记录表,在那之中EFCoreDatabaseContextBase唯有迁移记录3个表。
开创完现在还要把带迁移记录的协会保留下去,用作后边的争论统一,要是那里不保留会导致迁移记录的双重制造错误。

using (var context = new EFCoreDatabaseContextBase(Database, ConnectionString)) {
    // We may need create a new database and migration history table
    // It's done here
    context.Database.EnsureCreated();
    initialModel = context.Model;
}

在实践第一步事先,还索要先判定连接的数据库是或不是关周全据库,
因为Entity Framework Core现在还会支撑redis
mongodb等非关系型数据库,自动员搬迁移只应该用在关周详据库中。

using (var context = new EFCoreDatabaseContext(Database, ConnectionString)) {
    var serviceProvider = ((IInfrastructure<IServiceProvider>)context).Instance;
    var databaseCreator = serviceProvider.GetService<IDatabaseCreator>();
    if (databaseCreator is IRelationalDatabaseCreator) {
        // It's a relational database, create and apply the migration
        MigrateRelationalDatabase(context, initialModel);
    } else {
        // It maybe an in-memory database or no-sql database, do nothing
    }
}

其次步要求索求最后一条迁移记录,和目前的结构进行对照,寻觅差别并立异数据库。

先看迁移记录表的情节,迁移记录表中有七个字段

  • Revision 每一遍迁移都会+壹
  • Model 当前的结构,格式是c#代码
  • ProductVersion 迁移时Entity Framework Core的版本号

Model存放的代码例子如下,那段代码记录了全部表的全数字段的定义,是自动生成的。
背后小编将会讲课怎么样生成那段代码。

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using ZKWeb.ORM.EFCore;

namespace ZKWeb.ORM.EFCore.Migrations
{
    [DbContext(typeof(EFCoreDatabaseContext))]
    partial class Migration_636089159513819123 : ModelSnapshot
    {
        protected override void BuildModel(ModelBuilder modelBuilder)
        {
            modelBuilder
                .HasAnnotation("ProductVersion", "1.0.0-rtm-21431")
                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

            modelBuilder.Entity("Example.Entities.Foo", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd();

                    b.Property<string>("Name")
                        .IsRequired();
                });
            }
        }
    }
}

接下去查找最终一条迁移记录:

var lastModel = initialModel;
var histories = context.Set<EFCoreMigrationHistory>();
var lastMigration = histories.OrderByDescending(h => h.Revision).FirstOrDefault();

存在时,编写翻译Model中的代码并且赢得ModelSnapshot.Model的值,那一个值就是上二回迁移时的完整结构。
不设有时,将利用initialModel的结构。
编写翻译使用的是别的1个零件,你也得以用Roslyn CSharpScripting包提供的接口编写翻译。

if (lastMigration != null) {
    // Remove old snapshot code and assembly
    var tempPath = Path.GetTempPath();
    foreach (var file in Directory.EnumerateFiles(
        tempPath, ModelSnapshotFilePrefix + "*").ToList()) {
        try { File.Delete(file); } catch { }
    }
    // Write snapshot code to temp directory and compile it to assembly
    var assemblyName = ModelSnapshotFilePrefix + DateTime.UtcNow.Ticks;
    var codePath = Path.Combine(tempPath, assemblyName + ".cs");
    var assemblyPath = Path.Combine(tempPath, assemblyName + ".dll");
    var compileService = Application.Ioc.Resolve<ICompilerService>();
    var assemblyLoader = Application.Ioc.Resolve<IAssemblyLoader>();
    File.WriteAllText(codePath, lastMigration.Model);
    compileService.Compile(new[] { codePath }, assemblyName, assemblyPath);
    // Load assembly and create the snapshot instance
    var assembly = assemblyLoader.LoadFile(assemblyPath);
    var snapshot = (ModelSnapshot)Activator.CreateInstance(
        assembly.GetTypes().First(t =>
        typeof(ModelSnapshot).GetTypeInfo().IsAssignableFrom(t)));
    lastModel = snapshot.Model;
}

和脚下的组织举行对照:

// Compare with the newest model
var modelDiffer = serviceProvider.GetService<IMigrationsModelDiffer>();
var sqlGenerator = serviceProvider.GetService<IMigrationsSqlGenerator>();
var commandExecutor = serviceProvider.GetService<IMigrationCommandExecutor>();
var operations = modelDiffer.GetDifferences(lastModel, context.Model);
if (operations.Count <= 0) {
    // There no difference
    return;
}

假设有异样,生成迁移命令(commands)和当下总体结构的快速照相(modelSnapshot)。
上面Model中的代码由那里的CSharpMigrationsGenerator生成,modelSnapshot的体系是string

// There some difference, we need perform the migration
var commands = sqlGenerator.Generate(operations, context.Model);
var connection = serviceProvider.GetService<IRelationalConnection>();
// Take a snapshot to the newest model
var codeHelper = new CSharpHelper();
var generator = new CSharpMigrationsGenerator(
    codeHelper,
    new CSharpMigrationOperationGenerator(codeHelper),
    new CSharpSnapshotGenerator(codeHelper));
var modelSnapshot = generator.GenerateSnapshot(
    ModelSnapshotNamespace, context.GetType(),
    ModelSnapshotClassPrefix + DateTime.UtcNow.Ticks, context.Model);

安排迁移记录并执行迁移命令:

// Insert the history first, if migration failed, delete it
var history = new EFCoreMigrationHistory(modelSnapshot);
histories.Add(history);
context.SaveChanges();
try {
    // Execute migration commands
    commandExecutor.ExecuteNonQuery(commands, connection);
} catch {
    histories.Remove(history);
    context.SaveChanges();
    throw;
}

到此处就成功了Entity Framework
Core的机关迁移,以后每一趟有更新都会比较最后3回迁移时的构造并试行更新。
Entity Framework Core的迁移特点和Entity
Framework同样,能够确认保证很强的壹致性但需求小心理防线止数据的不见。

Entity Framework Core的活动员搬迁移

Entity Framework
Core去掉了SetInitializer慎选,替代它的是DatabaseFacade.MigrateDatabaseFacade.EnsureCreated
DatabaseFacade.Migrate能够使用使用ef命令生成的迁徙代码,防止在生产情状中实践ef命令。
DatabaseFacade.EnsureCreated则始于创立全体数据表和字段,但不得不创制不可能更新,不会加多纪录到__MigrationHistory
那七个函数都不能够兑现机关迁移,ZKWeb框架使用了EF内部提供的函数,完整代码能够查阅那里

Entity Framework Core的自发性迁移落成相比复杂,我们要求分两步走。

  • 率先步
    成立迁移记录__ZKWeb_MigrationHistory表,那么些表和EF自带的结构同样,但以此表是给本人用的不是给ef命令用的
  • 第一部
    查找最终一条迁移记录,和眼下的构造实行自己检查自纠,寻觅异样并更新数据库

首先步的代码应用了EnsureCreated开创数据库和迁移记录表,当中EFCoreDatabaseContextBase唯有迁移记录三个表。
始建完事后还要把带迁移记录的布局保留下去,用作前面包车型大巴对比,借使这里不保留会招致迁移记录的重复创设错误。

using (var context = new EFCoreDatabaseContextBase(Database, ConnectionString)) {
    // We may need create a new database and migration history table
    // It's done here
    context.Database.EnsureCreated();
    initialModel = context.Model;
}

在施行第2步事先,还亟需先判别连接的数据库是或不是关周全据库,
因为Entity Framework Core现在还会协助redis
mongodb等非关系型数据库,自动迁移只应该用在关全面据库中。

using (var context = new EFCoreDatabaseContext(Database, ConnectionString)) {
    var serviceProvider = ((IInfrastructure<IServiceProvider>)context).Instance;
    var databaseCreator = serviceProvider.GetService<IDatabaseCreator>();
    if (databaseCreator is IRelationalDatabaseCreator) {
        // It's a relational database, create and apply the migration
        MigrateRelationalDatabase(context, initialModel);
    } else {
        // It maybe an in-memory database or no-sql database, do nothing
    }
}

第三步需求寻觅最终一条迁移记录,和近期的构造进行自查自纠,寻觅异样并更新数据库。

先看迁移记录表的始末,迁移记录表中有七个字段

  • Revision 每便迁移都会+一
  • Model 当前的构造,格式是c#代码
  • ProductVersion 迁移时Entity Framework Core的本子号

Model存放的代码例子如下,那段代码记录了全体表的具有字段的概念,是自动生成的。
末端小编将会讲课怎么着生成那段代码。

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using ZKWeb.ORM.EFCore;

namespace ZKWeb.ORM.EFCore.Migrations
{
    [DbContext(typeof(EFCoreDatabaseContext))]
    partial class Migration_636089159513819123 : ModelSnapshot
    {
        protected override void BuildModel(ModelBuilder modelBuilder)
        {
            modelBuilder
                .HasAnnotation("ProductVersion", "1.0.0-rtm-21431")
                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

            modelBuilder.Entity("Example.Entities.Foo", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd();

                    b.Property<string>("Name")
                        .IsRequired();
                });
            }
        }
    }
}

接下去查找最终一条迁移记录:

var lastModel = initialModel;
var histories = context.Set<EFCoreMigrationHistory>();
var lastMigration = histories.OrderByDescending(h => h.Revision).FirstOrDefault();

留存时,编写翻译Model中的代码并且赢得ModelSnapshot.Model的值,这一个值正是上贰遍迁移时的全部结构。
不设有时,将选择initialModel的结构。
编写翻译使用的是别的贰个零部件,你也足以用Roslyn CSharpScripting包提供的接口编写翻译。

if (lastMigration != null) {
    // Remove old snapshot code and assembly
    var tempPath = Path.GetTempPath();
    foreach (var file in Directory.EnumerateFiles(
        tempPath, ModelSnapshotFilePrefix + "*").ToList()) {
        try { File.Delete(file); } catch { }
    }
    // Write snapshot code to temp directory and compile it to assembly
    var assemblyName = ModelSnapshotFilePrefix + DateTime.UtcNow.Ticks;
    var codePath = Path.Combine(tempPath, assemblyName + ".cs");
    var assemblyPath = Path.Combine(tempPath, assemblyName + ".dll");
    var compileService = Application.Ioc.Resolve<ICompilerService>();
    var assemblyLoader = Application.Ioc.Resolve<IAssemblyLoader>();
    File.WriteAllText(codePath, lastMigration.Model);
    compileService.Compile(new[] { codePath }, assemblyName, assemblyPath);
    // Load assembly and create the snapshot instance
    var assembly = assemblyLoader.LoadFile(assemblyPath);
    var snapshot = (ModelSnapshot)Activator.CreateInstance(
        assembly.GetTypes().First(t =>
        typeof(ModelSnapshot).GetTypeInfo().IsAssignableFrom(t)));
    lastModel = snapshot.Model;
}

和脚下的布局举行自己检查自纠:

// Compare with the newest model
var modelDiffer = serviceProvider.GetService<IMigrationsModelDiffer>();
var sqlGenerator = serviceProvider.GetService<IMigrationsSqlGenerator>();
var commandExecutor = serviceProvider.GetService<IMigrationCommandExecutor>();
var operations = modelDiffer.GetDifferences(lastModel, context.Model);
if (operations.Count <= 0) {
    // There no difference
    return;
}

万一有出入,生成迁移命令(commands)和当前全体结构的快速照相(modelSnapshot)。
地点Model中的代码由那里的CSharpMigrationsGenerator生成,modelSnapshot的种类是string

// There some difference, we need perform the migration
var commands = sqlGenerator.Generate(operations, context.Model);
var connection = serviceProvider.GetService<IRelationalConnection>();
// Take a snapshot to the newest model
var codeHelper = new CSharpHelper();
var generator = new CSharpMigrationsGenerator(
    codeHelper,
    new CSharpMigrationOperationGenerator(codeHelper),
    new CSharpSnapshotGenerator(codeHelper));
var modelSnapshot = generator.GenerateSnapshot(
    ModelSnapshotNamespace, context.GetType(),
    ModelSnapshotClassPrefix + DateTime.UtcNow.Ticks, context.Model);

安顿迁移记录并实行迁移命令:

// Insert the history first, if migration failed, delete it
var history = new EFCoreMigrationHistory(modelSnapshot);
histories.Add(history);
context.SaveChanges();
try {
    // Execute migration commands
    commandExecutor.ExecuteNonQuery(commands, connection);
} catch {
    histories.Remove(history);
    context.SaveChanges();
    throw;
}

到这里就完毕了Entity Framework
Core的自动员搬迁移,现在每便有革新都会比较最终三遍迁移时的社团并实践更新。
Entity Framework Core的迁徙特点和Entity
Framework一样,能够保险很强的一致性但供给专注防范数据的散失。

写入数据库

方今已成立了有Books表的数据库,也定义了模型和前后文类,然后可以用数码填充表。成立AddBookAsync方法将Book对象增加到数据库。首先,BooksContext对象被实例化,那里运用using语句确认保证数据库连接关闭。使用Add方法将对象加多到上下文之后,实体被写入调用SaveChangesAsync的数据库(代码文件BooksSample
/ Program.cs):

private async Task AddBookAsync(string title, string publisher)
{
  using (var context = new BooksContext())
  {
    var book = new Book
    {
      Title = title,
      Publisher = publisher
    };
    context.Add(book);
    int records = await context.SaveChangesAsync();

    WriteLine($"{records} record added");
  }
  WriteLine();
} 

要加多书籍列表,能够选取AddRange方法(代码文件BooksSample
/ Program.cs):

private async Task AddBooksAsync()
{
  using (var context = new BooksContext())
  {
    var b1 = new Book
    {
      Title ="Professional C# 5 and .NET 4.5.1",
      Publisher ="Wrox Press"
    };
    var b2 = new Book
    {
      Title ="Professional C# 2012 and .NET 4.5",
      Publisher ="Wrox Press"
    };
    var b3 = new Book
    {
      Title ="JavaScript for Kids",
      Publisher ="Wrox Press"
    };
    var b4 = new Book
    {
      Title ="Web Design with HTML and CSS",
      Publisher ="For Dummies"
    };
    context.AddRange(b1, b2, b3, b4);
    int records = await context.SaveChangesAsync();
    WriteLine($"{records} records added");
  }
  WriteLine();
} 

 运维应用程序并调用这个主意后,能够运用SQL
Server对象财富管理器查看写入到数据库的多寡。

写入数据库

前些天已开立了有Books表的数据库,也定义了模型和内外文类,然后能够用数码填充表。创造AddBookAsync方法将Book对象增添到数据库。首先,BooksContext对象被实例化,那里运用using语句确定保证数据库连接关闭。使用Add方法将目的加多到上下文之后,实体被写入调用SaveChangesAsync的数据库(代码文件BooksSample
/ Program.cs):

private async Task AddBookAsync(string title, string publisher)
{
  using (var context = new BooksContext())
  {
    var book = new Book
    {
      Title = title,
      Publisher = publisher
    };
    context.Add(book);
    int records = await context.SaveChangesAsync();

    WriteLine($"{records} record added");
  }
  WriteLine();
} 

要加多书籍列表,能够行使AddRange方法(代码文件BooksSample
/ Program.cs):

private async Task AddBooksAsync()
{
  using (var context = new BooksContext())
  {
    var b1 = new Book
    {
      Title ="Professional C# 5 and .NET 4.5.1",
      Publisher ="Wrox Press"
    };
    var b2 = new Book
    {
      Title ="Professional C# 2012 and .NET 4.5",
      Publisher ="Wrox Press"
    };
    var b3 = new Book
    {
      Title ="JavaScript for Kids",
      Publisher ="Wrox Press"
    };
    var b4 = new Book
    {
      Title ="Web Design with HTML and CSS",
      Publisher ="For Dummies"
    };
    context.AddRange(b1, b2, b3, b4);
    int records = await context.SaveChangesAsync();
    WriteLine($"{records} records added");
  }
  WriteLine();
} 

 运转应用程序并调用那些主意后,能够应用SQL
Server对象财富管理器查看写入到数据库的多寡。

写在结尾

自动员搬迁移数据库若是不易利用,能够提升项目中逐条模块的独立性,减弱支出和布署的工作量。
可是因为无法手动调控搬迁内容,有确定的局限和险恶,要求驾驭好应用的O本田CR-VM迁移的个性。

写在结尾

自动员搬迁移数据库假若不易行使,能够增长项目中逐条模块的独立性,裁减支出和布置的职业量。
唯独因为无法手动调整搬迁内容,有早晚的局限和产品险,必要理解好应用的OPRADOM迁移的特征。

从数据库读取

从C#代码读取数据只要求调用BooksContext并走访Books属性。访问此属性会创制多个SQL语句从数据库中寻找全部书籍(代码文件BooksSample
/ Program.cs):

private void ReadBooks()
{
  using (var context = new BooksContext())
  {
    var books = context.Books;
    foreach (var b in books)
    {
      WriteLine($"{b.Title} {b.Publisher}");
    }
  }
  WriteLine();
}

在调治时期张开速龙liTrace 伊芙nts窗口,可以看来发送到数据库的SQL语句(要求Visual
Studio 集团版):

SELECT [b].[BookId], [b].[Publisher], [b].[Title]
FROM [Books] AS [b]

Framework提供了八个LINQ提供程序,能够创制LINQ查询访问数据库。可以应用如下所示语法的章程:

private void QueryBooks()
{
  using (var context = new BooksContext())
  {
    var wroxBooks = context.Books.Where(b => b.Publisher =="Wrox Press");
    foreach (var b in wroxBooks)
    {
      WriteLine($"{b.Title} {b.Publisher}");
    }
  }
  WriteLine();
}

或利用LINQ查询语法:

var wroxBooks = from b in context.Books
                where b.Publisher =="Wrox Press"
                select b;

动用这二种分裂的语法,都将发送上边包车型大巴SQL语句到数据库:

SELECT [b].[BookId], [b].[Publisher], [b].[Title]
FROM [Books] AS [b]
WHERE [b].[Publisher] = 'Wrox Press'

*注意 在第1三章“语言集成查询”中详细议论了LINQ。
*

从数据库读取

从C#代码读取数据只需求调用BooksContext并走访Books属性。访问此属性会创制八个SQL语句从数据库中查找全体图书(代码文件Books萨姆ple
/ Program.cs):

private void ReadBooks()
{
  using (var context = new BooksContext())
  {
    var books = context.Books;
    foreach (var b in books)
    {
      WriteLine($"{b.Title} {b.Publisher}");
    }
  }
  WriteLine();
}

在调治时期打开AMDliTrace 伊夫nts窗口,能够见到发送到数据库的SQL语句(需求Visual
Studio 公司版):

SELECT [b].[BookId], [b].[Publisher], [b].[Title]
FROM [Books] AS [b]

Framework提供了3个LINQ提供程序,可以创制LINQ查询访问数据库。能够利用如下所示语法的不二等秘书诀:

private void QueryBooks()
{
  using (var context = new BooksContext())
  {
    var wroxBooks = context.Books.Where(b => b.Publisher =="Wrox Press");
    foreach (var b in wroxBooks)
    {
      WriteLine($"{b.Title} {b.Publisher}");
    }
  }
  WriteLine();
}

或选取LINQ查询语法:

var wroxBooks = from b in context.Books
                where b.Publisher =="Wrox Press"
                select b;

选取那三种区别的语法,都将发送上面包车型的士SQL语句到数据库:

SELECT [b].[BookId], [b].[Publisher], [b].[Title]
FROM [Books] AS [b]
WHERE [b].[Publisher] = 'Wrox Press'

*注意 在第3三章“语言集成查询”中详细座谈了LINQ。
*

写在最终的广告

ZKWeb网页框架曾经在骨子里项目中利用了那项才能,最近来看迁移部分照旧比较牢固的。
那项才能最初是为了插件市四而开垦的,在下载安装插件未来不须要重新编写翻译主程序,不供给实施其余迁移命令就能应用。
当前纵然尚未实现插件百货店,也缩减了广大数见不鲜费用的劳作。

一经你有意思味,招待到场ZKWeb交换群5220838八6协助实行查究。

写在结尾的广告

ZKWeb网页框架曾经在实际上项目中使用了那项技术,目前来看迁移部分如故相比较牢固的。
那项技能最初是为着插件市4而支出的,在下载安装插件现在不供给再行编写翻译主程序,不须求实行别的迁移命令就能利用。
时下就算尚无完成插件商场,也减小了不少普普通通费用的做事。

假诺你有意思味,接待到场ZKWeb交换群52208388六一齐研商。

革新记录

只需更换已加载上下文的目标并调用SaveChangesAsync就能够轻易达成立异记录(代码文件BooksSample
/ Program.cs):

private async Task UpdateBookAsync()
{
  using (var context = new BooksContext())
  {
    int records = 0;
    var book = context.Books.Where(b => b.Title =="Professional C# 6")
      .FirstOrDefault();
    if (book != null)
    {
      book.Title ="Professional C# 6 and .NET Core 5";
      records = await context.SaveChangesAsync();
    }
    WriteLine($"{records} record updated");
  }
  WriteLine();
}

创新记录

只需退换已加载上下文的目的并调用SaveChangesAsync就可以轻巧落成立异记录(代码文件BooksSample
/ Program.cs):

private async Task UpdateBookAsync()
{
  using (var context = new BooksContext())
  {
    int records = 0;
    var book = context.Books.Where(b => b.Title =="Professional C# 6")
      .FirstOrDefault();
    if (book != null)
    {
      book.Title ="Professional C# 6 and .NET Core 5";
      records = await context.SaveChangesAsync();
    }
    WriteLine($"{records} record updated");
  }
  WriteLine();
}

删去记录

最终,让我们清理数据库并删除全体记录。能够由此查找全数记录并调用Remove或RemoveRange方法来安装上下文中要去除的对象的气象。然后调用SaveChangesAsync方法就可以从数据库中去除记录,DbContext会为各种要刨除的靶子调用SQL
Delete语句(代码文件BooksSample / Program.cs):

private async Task DeleteBooksAsync()
{
  using (var context = new BooksContext())
  {
    var books = context.Books;
    context.Books.RemoveRange(books);
    int records = await context.SaveChangesAsync();
    WriteLine($"{records} records deleted");
  }
  WriteLine();
}

*注意 对象关联映射工具(如Entity
Framework)在毫不在具有方案中都可用。使用示例代码不可能有效地删除全体目的。您能够采用贰个SQL语句删除全部而不是逐条删除记录。在第三七章“ADO.NET”中表达了何以成功那或多或少。*

问询了何等增添、查询、更新和删除记录,本章将介绍幕后的效果,并应用Entity
Framework进入高等场景。

删去记录

最终,让我们清理数据库并删除全体记录。能够经过搜索全体记录并调用Remove或RemoveRange方法来安装上下文中要删减的靶子的图景。然后调用SaveChangesAsync方法就能够从数据库中剔除记录,DbContext会为各种要刨除的目标调用SQL
Delete语句(代码文件BooksSample / Program.cs):

private async Task DeleteBooksAsync()
{
  using (var context = new BooksContext())
  {
    var books = context.Books;
    context.Books.RemoveRange(books);
    int records = await context.SaveChangesAsync();
    WriteLine($"{records} records deleted");
  }
  WriteLine();
}

*注意 目的关联映射工具(如Entity
Framework)在毫不在装有方案中都可用。使用示例代码不能有效地删除全体目的。您能够运用三个SQL语句删除全体而不是逐条删除记录。在第二7章“ADO.NET”中表明了怎么着产生那或多或少。*

摸底了什么增添、查询、更新和删除记录,本章将介绍幕后的功力,并选拔Entity
Framework进入高级场景。

应用注重注入  

Entity
Framework Core 一.0放手了对借助注入的支撑。连接和SQL
Server采纳能够透过动用依赖注入框架注入,而非定义和接下来利用DbContext派生类的SQL
Server连接。 

要翻开此操作,Books萨姆pleWithDI示例项目对上三个代码示例项目展开了改变。 

此示例使用以下依赖项和命名空间:

  依赖项

NETStandard.Library
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.Framework.DependencyInjection 

  命名空间

Microsoft.EntityFrameworkCore
System.Linq
System.Threading.Tasks
static System.Console

BooksContext类现在看起来很简单,只需定义Books属性(代码文件BooksSampleWithDI
/ BooksContext.cs):

public class BooksContext: DbContext
{
  public DbSet<Book> Books { get; set; }
}

Books瑟维斯是应用BooksContext的新类。BooksContext通过注入构造函数注入。方法AddBooksAsync和ReadBooks与上一个演示中的这一个主意足够相像,但他俩运用BooksService类的上下文成员,而不是创办2个新的(代码文件Books萨姆pleWithDI
/ BooksService.cs):

public class BooksService
{
  private readonly BooksContext _booksContext;
  public BooksService(BooksContext context)
  {
    _booksContext = context;
  }

  public async Task AddBooksAsync()
  {
    var b1 = new Book
    {
      Title ="Professional C# 5 and .NET 4.5.1",
      Publisher ="Wrox Press"
    };
    var b2 = new Book
    {
      Title ="Professional C# 2012 and .NET 4.5",
      Publisher ="Wrox Press"
    };
    var b3 = new Book
    {
      Title ="JavaScript for Kids",
      Publisher ="Wrox Press"
    };
    var b4 = new Book
    {
      Title ="Web Design with HTML and CSS",
      Publisher ="For Dummies"
    };
    _booksContext.AddRange(b1, b2, b3, b4);
    int records = await _booksContext.SaveChangesAsync();

    WriteLine($"{records} records added");
  }

  public void ReadBooks()
  {
    var books = _booksContext.Books;
    foreach (var b in books)
    {
      WriteLine($"{b.Title} {b.Publisher}");
    }
    WriteLine();
  }
} 

依附注入框架的容器在
Initialize瑟维斯s
方法中起头化。创制3个ServiceCollection实例,将BooksService类增加到此汇集中,并开始展览目前生命周期管理。那样,每趟请求该服务时都会实例化
瑟维斯Collection。对于注册Entity Framework和SQL
Server,能够用增添方法AddEntityFramework,AddSqlServer和AddDbContext。
AddDbContext方法需求四个Action委托作为参数,当中接收到二个DbContextOptionsBuilder参数。有了该选项参数,可以应用UseSqlServer扩大方法配置上下文。这里用Entity
Framework注册SQL
Server与上三个示范是近似的作用(代码文件BooksSampleWithDI /
Program.cs):

private void InitializeServices()
{
  const string ConnectionString =@"server= (localdb)\MSSQLLocalDb;database=Books;trusted_connection=true";
  var services = new ServiceCollection();
  services.AddTransient<BooksService>();
  services.AddEntityFramework()
    .AddSqlServer()
    .AddDbContext<BooksContext>(options =>
      options.UseSqlServer(ConnectionString));
  Container = services.BuildServiceProvider();
}

public IServiceProvider Container { get; private set; }

服务的伊始化以及BooksService的应用是从Main方法成功的。通过调用IServiceProvider的GetService方法来搜寻BooksService(代码文件Books山姆pleWithDI
/ Program.cs):

static void Main()
{
  var p = new Program();
  p.InitializeServices();

  var service = p.Container.GetService<BooksService>();
  service.AddBooksAsync().Wait();
  service.ReadBooks();
}

运营应用程序能够看来记录已加多到图书数据库中然后从中读取记录。

*注意
在第一一章“XAML应用程序的格局”中读书有关信赖注入和Microsoft.Framework.DependencyInjection包的更多音信,仍是能够敬重第50章“ASP.NET
Core”和第伍1章“ ASP.NET MVC“。*

使用注重注入  

Entity
Framework Core 一.0放到了对借助注入的支撑。连接和SQL
Server选拔能够通过运用注重注入框架注入,而非定义和接下来使用DbContext派生类的SQL
Server连接。 

要查阅此操作,BooksSampleWithDI示例项目对上叁个代码示例项目进展了修改。 

此示例使用以下信赖项和命名空间:

  依赖项

NETStandard.Library
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.Framework.DependencyInjection 

  命名空间

Microsoft.EntityFrameworkCore
System.Linq
System.Threading.Tasks
static System.Console

BooksContext类现在看起来很轻便,只需定义Books属性(代码文件BooksSampleWithDI
/ BooksContext.cs):

public class BooksContext: DbContext
{
  public DbSet<Book> Books { get; set; }
}

BooksService是使用BooksContext的新类。BooksContext通过注入构造函数注入。方法AddBooksAsync和ReadBooks与上叁个演示中的这个点子充足相像,但他们使用BooksService类的上下文成员,而不是开创多少个新的(代码文件Books萨姆pleWithDI
/ BooksService.cs):

public class BooksService
{
  private readonly BooksContext _booksContext;
  public BooksService(BooksContext context)
  {
    _booksContext = context;
  }

  public async Task AddBooksAsync()
  {
    var b1 = new Book
    {
      Title ="Professional C# 5 and .NET 4.5.1",
      Publisher ="Wrox Press"
    };
    var b2 = new Book
    {
      Title ="Professional C# 2012 and .NET 4.5",
      Publisher ="Wrox Press"
    };
    var b3 = new Book
    {
      Title ="JavaScript for Kids",
      Publisher ="Wrox Press"
    };
    var b4 = new Book
    {
      Title ="Web Design with HTML and CSS",
      Publisher ="For Dummies"
    };
    _booksContext.AddRange(b1, b2, b3, b4);
    int records = await _booksContext.SaveChangesAsync();

    WriteLine($"{records} records added");
  }

  public void ReadBooks()
  {
    var books = _booksContext.Books;
    foreach (var b in books)
    {
      WriteLine($"{b.Title} {b.Publisher}");
    }
    WriteLine();
  }
} 

依傍注入框架的容器在
InitializeServices
方法中开头化。创设三个ServiceCollection实例,将BooksService类增加到此汇集中,并拓展暂且生命周期管理。那样,每趟请求该服务时都会实例化
ServiceCollection。对于注册Entity Framework和SQL
Server,能够用扩充方法AddEntityFramework,AddSqlServer和AddDbContext。
AddDbContext方法供给二个Action委托作为参数,当中接收到四个DbContextOptionsBuilder参数。有了该选项参数,能够选取UseSqlServer扩充方法配置上下文。那里用Entity
Framework注册SQL
Server与上2个示范是类似的功能(代码文件Books萨姆pleWithDI /
Program.cs):

private void InitializeServices()
{
  const string ConnectionString =@"server= (localdb)\MSSQLLocalDb;database=Books;trusted_connection=true";
  var services = new ServiceCollection();
  services.AddTransient<BooksService>();
  services.AddEntityFramework()
    .AddSqlServer()
    .AddDbContext<BooksContext>(options =>
      options.UseSqlServer(ConnectionString));
  Container = services.BuildServiceProvider();
}

public IServiceProvider Container { get; private set; }

劳动的开始化以及BooksService的选择是从Main方法成功的。通过调用IServiceProvider的GetService方法来索求BooksService(代码文件Books萨姆pleWithDI
/ Program.cs):

static void Main()
{
  var p = new Program();
  p.InitializeServices();

  var service = p.Container.GetService<BooksService>();
  service.AddBooksAsync().Wait();
  service.ReadBooks();
}

运作应用程序可以看到记录已增加到图书数据库中然后从中读取记录。

*注意
在第二一章“XAML应用程序的方式”中读书有关注重注入和Microsoft.Framework.DependencyInjection包的越来越多消息,还能景仰第陆0章“ASP.NET
Core”和第陆1章“ ASP.NET MVC“。*

始建立模型型  

本章的首先个示例映射单个表。第一个例证显示了成立表之间的关系。在本节中利用C#代码创立数据库而尚未采用SQL
DDL语句(或透过选择设计器)创造数据库。 

演示应用程序MenusSample使用以下重视项和命名空间:

  依赖项

NETStandard.Library
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer

  命名空间

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.ChangeTracking
System
System.Collections.Generic
System.ComponentModel.DataAnnotations
System.ComponentModel.DataAnnotations.Schema
System.Linq
System.Threading
System.Threading.Tasks
static System.Console

成立模型  

本章的首先个示例映射单个表。第四个例子显示了创制表之间的关系。在本节中采用C#代码创造数据库而未有选取SQL
DDL语句(或通过使用设计器)创立数据库。 

示范应用程序Menus萨姆ple使用以下依赖项和命名空间:

  依赖项

NETStandard.Library
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer

  命名空间

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.ChangeTracking
System
System.Collections.Generic
System.ComponentModel.DataAnnotations
System.ComponentModel.DataAnnotations.Schema
System.Linq
System.Threading
System.Threading.Tasks
static System.Console

创办关系

让我们开端创办四个模型。示例项目采用MenuCard和Menu类型定义壹对多涉及。MenuCard包蕴Menu对象的列表。那种涉及由List
<Menu>类型的Menu属性简单定义(代码文件MenusSample /
MenuCard.cs):

public class MenuCard
{
  public int MenuCardId { get; set; }
  public string Title { get; set; }
  public List<Menu> Menus { get; } = new List<Menu>();

  public override string ToString() => Title;
}

该关系也能够从另2个角度访问,菜单能够利用MenuCard属性访问MenuCard。钦定MenuCardId 属性去定义外键关系(代码文件Menus萨姆ple / Menu.cs):

public class Menu
{
  public int MenuId { get; set; }
  public string Text { get; set; }
  public decimal Price { get; set; }

  public int MenuCardId { get; set; }
  public MenuCard MenuCard { get; set; }

  public override string ToString() => Text;
}

到数据库的照射由MenusContext类落成。那几个类定义为与上一个上下文类型类似的体系,它只含有二日个性来映射五个对象类型:属性Menus和MenuCards(代码文件Menus山姆ples
/ MenusContext.cs):

public class MenusContext: DbContext
{
  private const string ConnectionString = @"server=(localdb)\MSSQLLocalDb;" +     "Database=MenuCards;Trusted_Connection=True";
  public DbSet<Menu> Menus { get; set; }
  public DbSet<MenuCard> MenuCards { get; set; }

  protected override void OnConfiguring(DbContextOptionsBuilder  optionsBuilder)
  {
    base.OnConfiguring(optionsBuilder);
    optionsBuilder.UseSqlServer(ConnectionString);
  }
}

创造关系

让我们开首创设贰个模子。示例项目利用MenuCard和Menu类型定义壹对多涉及。MenuCard包涵Menu对象的列表。那种关系由List
<Menu>类型的Menu属性轻松定义(代码文件MenusSample /
MenuCard.cs):

public class MenuCard
{
  public int MenuCardId { get; set; }
  public string Title { get; set; }
  public List<Menu> Menus { get; } = new List<Menu>();

  public override string ToString() => Title;
}

该关系也得以从另1个角度访问,菜单能够应用Menu卡德属性访问MenuCard。内定MenuCardId 属性去定义外键关系(代码文件Menus萨姆ple / Menu.cs):

public class Menu
{
  public int MenuId { get; set; }
  public string Text { get; set; }
  public decimal Price { get; set; }

  public int MenuCardId { get; set; }
  public MenuCard MenuCard { get; set; }

  public override string ToString() => Text;
}

到数据库的照耀由MenusContext类落成。这一个类定义为与上三个光景文类型类似的项目,它只包罗七个性子来映射多个目的类型:属性Menus和MenuCards(代码文件Menus萨姆ples
/ MenusContext.cs):

public class MenusContext: DbContext
{
  private const string ConnectionString = @"server=(localdb)\MSSQLLocalDb;" +     "Database=MenuCards;Trusted_Connection=True";
  public DbSet<Menu> Menus { get; set; }
  public DbSet<MenuCard> MenuCards { get; set; }

  protected override void OnConfiguring(DbContextOptionsBuilder  optionsBuilder)
  {
    base.OnConfiguring(optionsBuilder);
    optionsBuilder.UseSqlServer(ConnectionString);
  }
}

使用.NET CLI进行搬迁

要接纳C#代码自动创立数据库,能够应用enet工具使用package
dotnet-ef扩大.NET
CLI工具。此软件手提袋含用于为搬迁创建C#代码的吩咐。通过设置dotnet-ef
NuGet包能够任务令可用。您能够通过从品类布局文件(代码文件Menus萨姆ple /
project.json)中的工具部分引用此软件包来设置它:

"tools": {
  "dotnet-ef":"1.0.0-*"
 }

ef命令提供以下命令:数据库、dbcontext和迁移。数据库命令用于将数据库进级到一定的搬迁情状。
dbcontext命令列出项目中的全部DbContext派生类型(dbcontext
list),并从数据库(dbcontext scaffold)创建上下文和实业。
migrations命令则开创和删除迁移,以及开创SQL脚本去创制包蕴全部迁移的数据库。若是生产数据库只好从SQL管理员使用SQL代码创立和更动,可以将调换的本子移交给SQL管理员。 

为了成立起来迁移以从代码创立数据库,能够从开采职员命令提醒符调用以下命令,该命令创立名叫InitMenuCards的搬迁:

>dotnet ef migrations add InitMenuCards

一声令下migrations
add使用反射以及相反的引用模型访问DbContext派生类。此音讯创制多少个类来创建和更新数据库。使用Menu,Menu卡德和MenusContext类成立四个类,MenusContextModelSnapshot和InitMenuCards。命令成功后能够在Migrations文件夹中找到那二种等级次序。

MenusContextModelSnapshot类包涵创设数据库的模型的此时此刻景观:

[DbContext(typeof(MenusContext))]
partial class MenusContextModelSnapshot: ModelSnapshot
{
  protected override void BuildModel(ModelBuilder modelBuilder)
  {
    modelBuilder
     .HasAnnotation("ProductVersion","7.0.0-rc1-16348")
     .HasAnnotation("SqlServer:ValueGenerationStrategy",
       SqlServerValueGenerationStrategy.IdentityColumn);

     modelBuilder.Entity("MenusSample.Menu", b =>
     {
       b.Property<int>("MenuId")
        .ValueGeneratedOnAdd();
       b.Property<int>("MenuCardId");
       b.Property<decimal>("Price");
       b.Property<string>("Text");
       b.HasKey("MenuId");
     });

     modelBuilder.Entity("MenusSample.MenuCard", b =>
     {
       b.Property<int>("MenuCardId")
        .ValueGeneratedOnAdd();

       b.Property<string>("Title");
       b.HasKey("MenuCardId");
     });
     modelBuilder.Entity("MenusSample.Menu", b =>
     {
       b.HasOne("MenusSample.MenuCard")
        .WithMany()
        .HasForeignKey("MenuCardId");
     });
  }
}

InitMenuCards类定义了Up和Down方法。
Up方法列出了成立MenuCard和菜单表所需的享有操作,包含主键、列和关联。
Down方法删除多少个表:

public partial class InitMenuCards: Migration
{
  protected override void Up(MigrationBuilder migrationBuilder)
  {
    migrationBuilder.CreateTable(
      name:"MenuCard",
      columns: table => new
      {
        MenuCardId = table.Column<int>(nullable: false)
          .Annotation("SqlServer:ValueGenerationStrategy",
            SqlServerValueGenerationStrategy.IdentityColumn),
        Title = table.Column<string>(nullable: true)
      },
      constraints: table =>
      {
        table.PrimaryKey("PK_MenuCard", x => x.MenuCardId);
      });

    migrationBuilder.CreateTable(
      name:"Menu",
      columns: table => new
      {
        MenuId = table.Column<int>(nullable: false)
          .Annotation("SqlServer:ValueGenerationStrategy",
            SqlServerValueGenerationStrategy.IdentityColumn),
        MenuCardId = table.Column<int>(nullable: false),
        Price = table.Column<decimal>(nullable: false),
        Text = table.Column<string>(nullable: true)
      },
      constraints: table =>
      {
        table.PrimaryKey("PK_Menu", x => x.MenuId);
        table.ForeignKey(
          name:"FK_Menu_MenuCard_MenuCardId",
          column: x => x.MenuCardId,
          principalTable:"MenuCard",
          principalColumn:"MenuCardId",
          onDelete: ReferentialAction.Cascade);
      });
  }

  protected override void Down(MigrationBuilder migrationBuilder)
  {
    migrationBuilder.DropTable("Menu");
    migrationBuilder.DropTable("MenuCard");
  }
}

注意 正在进展的各种退换都得以创设另3个搬迁。新搬迁仅定义从原先版本到新本子所需的改造。假若客户的数据库供给从随机早期的本子更新,迁移数据库时调用供给的搬迁。 

在付出进度中,也行不必要全体的迁移,大概要求从类型中开创,因为大概未有该类目前气象的数据仓库储存在。在那种气象下能够去除迁移并创制三个非常大的新搬迁。

使用.NET CLI实行搬迁

要使用C#代码自动成立数据库,可以动用enet工具使用package
dotnet-ef扩大.NET
CLI工具。此软件单肩包含用于为搬迁成立C#代码的吩咐。通过设置dotnet-ef
NuGet包能够职务令可用。您能够透过从品类配置文件(代码文件Menus萨姆ple /
project.json)中的工具部分引用此软件包来设置它:

"tools": {
  "dotnet-ef":"1.0.0-*"
 }

ef命令提供以下命令:数据库、dbcontext和迁移。数据库命令用于将数据库进级到一定的迁移情状。
dbcontext命令列出项目中的全数DbContext派生类型(dbcontext
list),并从数据库(dbcontext scaffold)创立上下文和实业。
migrations命令则开创和删除迁移,以及开创SQL脚本去成立包括全体迁移的数据库。假使生产数据库只可以从SQL管理员使用SQL代码创建和改造,能够将扭转的台本移交给SQL管理员。 

为了创造起来迁移以从代码创制数据库,能够从开辟职员命令提醒符调用以下命令,该命令创造名字为InitMenuCards的迁移:

>dotnet ef migrations add InitMenuCards

指令migrations
add使用反射以及相反的引用模型访问DbContext派生类。此音信创立四个类来创立和立异数据库。使用Menu,MenuCard和MenusContext类创造几个类,MenusContextModelSnapshot和InitMenuCards。命令成功后得以在Migrations文件夹中找到这三种等级次序。

MenusContextModelSnapshot类包蕴创设数据库的模型的当前情景:

[DbContext(typeof(MenusContext))]
partial class MenusContextModelSnapshot: ModelSnapshot
{
  protected override void BuildModel(ModelBuilder modelBuilder)
  {
    modelBuilder
     .HasAnnotation("ProductVersion","7.0.0-rc1-16348")
     .HasAnnotation("SqlServer:ValueGenerationStrategy",
       SqlServerValueGenerationStrategy.IdentityColumn);

     modelBuilder.Entity("MenusSample.Menu", b =>
     {
       b.Property<int>("MenuId")
        .ValueGeneratedOnAdd();
       b.Property<int>("MenuCardId");
       b.Property<decimal>("Price");
       b.Property<string>("Text");
       b.HasKey("MenuId");
     });

     modelBuilder.Entity("MenusSample.MenuCard", b =>
     {
       b.Property<int>("MenuCardId")
        .ValueGeneratedOnAdd();

       b.Property<string>("Title");
       b.HasKey("MenuCardId");
     });
     modelBuilder.Entity("MenusSample.Menu", b =>
     {
       b.HasOne("MenusSample.MenuCard")
        .WithMany()
        .HasForeignKey("MenuCardId");
     });
  }
}

InitMenuCards类定义了Up和Down方法。
Up方法列出了创制Menu卡德和菜单表所需的保有操作,包罗主键、列和关联。
Down方法删除七个表:

public partial class InitMenuCards: Migration
{
  protected override void Up(MigrationBuilder migrationBuilder)
  {
    migrationBuilder.CreateTable(
      name:"MenuCard",
      columns: table => new
      {
        MenuCardId = table.Column<int>(nullable: false)
          .Annotation("SqlServer:ValueGenerationStrategy",
            SqlServerValueGenerationStrategy.IdentityColumn),
        Title = table.Column<string>(nullable: true)
      },
      constraints: table =>
      {
        table.PrimaryKey("PK_MenuCard", x => x.MenuCardId);
      });

    migrationBuilder.CreateTable(
      name:"Menu",
      columns: table => new
      {
        MenuId = table.Column<int>(nullable: false)
          .Annotation("SqlServer:ValueGenerationStrategy",
            SqlServerValueGenerationStrategy.IdentityColumn),
        MenuCardId = table.Column<int>(nullable: false),
        Price = table.Column<decimal>(nullable: false),
        Text = table.Column<string>(nullable: true)
      },
      constraints: table =>
      {
        table.PrimaryKey("PK_Menu", x => x.MenuId);
        table.ForeignKey(
          name:"FK_Menu_MenuCard_MenuCardId",
          column: x => x.MenuCardId,
          principalTable:"MenuCard",
          principalColumn:"MenuCardId",
          onDelete: ReferentialAction.Cascade);
      });
  }

  protected override void Down(MigrationBuilder migrationBuilder)
  {
    migrationBuilder.DropTable("Menu");
    migrationBuilder.DropTable("MenuCard");
  }
}

注意 正在举办的每一种改造都得以创建另一个搬迁。新搬迁仅定义从原先版本到新本子所需的更换。固然客户的数据库须求从随机早期的版本更新,迁移数据库时调用要求的动员搬迁。 

在支付进程中,也行不必要持有的迁移,大概供给从品类中创立,因为恐怕未有该类一时半刻气象的数据库存在。在那种情状下能够去除迁移并创立二个相当大的新搬迁。

动用MSBuild实行搬迁  

如果你正在使用基于MSBuild的项目Entity
Framework迁移而不是DNX,迁移命令是见仁见智的。使用完整框架调节台应用程序、WPF应用程序或ASP.NET
四.陆项目项目,要求在NuGet包管理器调控毕尔巴鄂钦命迁移命令,而不是开采人士命令提醒符。从Visual
Studio通过 工具➪库处理器调节台➪包处理器调节台
运转包管理器调节台。

在包管理器调节台能够运用PowerShell脚本增添和删除迁移。命令如下

> Add-Migration InitMenuCards

创制八个Migrations文件夹,在那之中蕴含如前所示的迁移类。

创立数据库 

趁着迁移类型形成,能够创造数据库。
DbContext派生类MenusContext包蕴2个回来DatabaseFacade对象的Database属性。使用DatabaseFacade能够创制和删除数据库。假若数据库不设有,EnsureCreated方法会创立数据库;纵然数据库已存在,则不试行别的操作。方法EnsureDeletedAsync删除数据库。以下代码片段成立数据库(假如它不设有)(代码文件MenusSample
/ Program.cs):

private static async Task CreateDatabaseAsync()
{
  using (var context = new MenusContext())
  {
bool created = await context.Database.EnsureCreatedAsync();
    string createdText = created ?"created":"already exists";
    WriteLine($"database {createdText}");
  }
}

注意 设若数据库存在不过1个较旧的构造版本,EnsureCreatedAsync方法不会选择结构更动。那时能够因而调用Migrate方法来张开布局晋级。
Migrate是Microsoft.Data.Entity命名空间中定义的DatabaseFacade类的扩张方法。

运作程序将创立表MenuCard和Menu。基于暗许约定,表与实体类型是同等的名称。另三个预订用于成立主键:MenuCardId列会被定义为主键,因为属性名以Id截至。

CREATE TABLE [dbo].[MenuCard] (
  [MenuCardId] INT            IDENTITY (1, 1) NOT NULL,
  [Title]      NVARCHAR (MAX) NULL,
  CONSTRAINT [PK_MenuCard] PRIMARY KEY CLUSTERED ([MenuCardId] ASC)
);

Menu表定义了MenuCardId,它是MenuCard表的外键。由于DELETE
CASCADE,删除Menu卡德也会去除全部关乎的Menu行:

CREATE TABLE [dbo].[Menu] (
  [MenuId]     INT             IDENTITY (1, 1) NOT NULL,
  [MenuCardId] INT             NOT NULL,
  [Price]      DECIMAL (18, 2) NOT NULL,
  [Text]       NVARCHAR (MAX)  NULL,
  CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED ([MenuId] ASC),
  CONSTRAINT [FK_Menu_MenuCard_MenuCardId] FOREIGN KEY ([MenuCardId])
  REFERENCES [dbo].[MenuCard] ([MenuCardId]) ON DELETE CASCADE
);

在创设代码中有一部分有的退换是行得通的。比方,Text
和 Title 列的大大小小能够从NVALacrosseCHA牧马人(MAX)减小,SQL
Server定义了可用以Price列的Money类型,并且协会名称能够从dbo更换。 Entity
Framework提供了多少个选拔从代码中实践那么些改造:数据解说和Fluent
API,下边将探讨。

多少讲解

影响生成的数据库的壹种艺术是向实体类型丰硕数据注释。能够选择Table属性改变表的名号。要改成结构名称,Table属性定义Schema属性。假如要为字符串类型钦命分化的长度,可以动用马克斯Length属性(代码文件MenusWithDataAnnotations
/ MenuCard.cs):

[Table("MenuCards", Schema ="mc")]
public class MenuCard
{
  public int MenuCardId { get; set; }
  [MaxLength(120)]
  public string Title { get; set; }
  public List<Menu> Menus { get; }
}

Menu类的Table和马克斯Length属性一样能够利用。使用Column属性改换SQL类型(代码文件MenusWithDataAnnotations
/ Menu.cs):

[Table("Menus", Schema ="mc")]
public class Menu
{
  public int MenuId { get; set; }
  [MaxLength(50)]
  public string Text { get; set; }
  [Column(TypeName ="Money")]
  public decimal Price { get; set; }
  public int MenuCardId { get; set; }
  public MenuCard MenuCard { get; set; }
}

动用迁移创造数据库后得以见到结构名称下表的新名称,以及Title、Text
和 Price 字段中已改变的数据类型:

CREATE TABLE [mc].[MenuCards] (
  [MenuCardId] INT            IDENTITY (1, 1) NOT NULL,
  [Title]      NVARCHAR (120) NULL,
  CONSTRAINT [PK_MenuCard] PRIMARY KEY CLUSTERED ([MenuCardId] ASC)
);

CREATE TABLE [mc].[Menus] (
  [MenuId]     INT           IDENTITY (1, 1) NOT NULL,
  [MenuCardId] INT           NOT NULL,
  [Price]      MONEY         NOT NULL,
  [Text]       NVARCHAR (50) NULL,
  CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED ([MenuId] ASC),
  CONSTRAINT [FK_Menu_MenuCard_MenuCardId] FOREIGN KEY ([MenuCardId])
    REFERENCES [mc].[MenuCards] ([MenuCardId]) ON DELETE CASCADE
);

利用MSBuild举行搬迁  

要是您正在使用基于MSBuild的项目Entity
Framework迁移而不是DNX,迁移命令是见仁见智的。使用完全框架调整台应用程序、WPF应用程序或ASP.NET
4.陆品类体系,要求在NuGet包管理器调控埃德蒙顿钦赐迁移命令,而不是开辟职员命令提醒符。从Visual
Studio通过 工具➪库管理器调节台➪包管理器调控台
运维包管理器调控台。

在包管理器调节台能够使用PowerShell脚本加多和删除迁移。命令如下

> Add-Migration InitMenuCards

制造一个Migrations文件夹,个中富含如前所示的迁移类。

创办数据库 

随着迁移类型形成,能够成立数据库。
DbContext派生类MenusContext包涵一个重临DatabaseFacade对象的Database属性。使用DatabaseFacade能够创设和删除数据库。要是数据库不设有,EnsureCreated方法会创造数据库;尽管数据库已存在,则不施行此外操作。方法EnsureDeletedAsync删除数据库。以下代码片段创设数据库(假若它不存在)(代码文件Menus萨姆ple
/ Program.cs):

private static async Task CreateDatabaseAsync()
{
  using (var context = new MenusContext())
  {
bool created = await context.Database.EnsureCreatedAsync();
    string createdText = created ?"created":"already exists";
    WriteLine($"database {createdText}");
  }
}

注意 假设数据库存在但是四个较旧的组织版本,EnsureCreatedAsync方法不会采取结构退换。那时能够由此调用Migrate方法来张开结构晋级。
Migrate是Microsoft.Data.Entity命名空间中定义的DatabaseFacade类的庞大方法。

运作程序将开创表MenuCard和Menu。基于暗许约定,表与实业类型是平等的名目。另二个预订用于成立主键:MenuCardId列会被定义为主键,因为属性名以Id甘休。

CREATE TABLE [dbo].[MenuCard] (
  [MenuCardId] INT            IDENTITY (1, 1) NOT NULL,
  [Title]      NVARCHAR (MAX) NULL,
  CONSTRAINT [PK_MenuCard] PRIMARY KEY CLUSTERED ([MenuCardId] ASC)
);

Menu表定义了MenuCardId,它是MenuCard表的外键。由于DELETE
CASCADE,删除MenuCard也会去除全数涉嫌的Menu行:

CREATE TABLE [dbo].[Menu] (
  [MenuId]     INT             IDENTITY (1, 1) NOT NULL,
  [MenuCardId] INT             NOT NULL,
  [Price]      DECIMAL (18, 2) NOT NULL,
  [Text]       NVARCHAR (MAX)  NULL,
  CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED ([MenuId] ASC),
  CONSTRAINT [FK_Menu_MenuCard_MenuCardId] FOREIGN KEY ([MenuCardId])
  REFERENCES [dbo].[MenuCard] ([MenuCardId]) ON DELETE CASCADE
);

在开创代码中有一部分有的改换是立竿见影的。举例,Text
和 Title 列的高低能够从NVARubiconCHA大切诺基(MAX)减小,SQL
Server定义了可用于Price列的Money类型,并且组织名称可以从dbo改变。 Entity
Framework提供了多少个选用从代码中实践这几个改变:数据讲明和Fluent
API,上面将研究。

数据疏解

影响生成的数据库的一种格局是向实体类型丰盛数据注释。能够使用Table属性退换表的名号。要更动结构名称,Table属性定义Schema属性。即便要为字符串类型钦定差异的尺寸,能够利用马克斯Length属性(代码文件MenusWithDataAnnotations
/ MenuCard.cs):

[Table("MenuCards", Schema ="mc")]
public class MenuCard
{
  public int MenuCardId { get; set; }
  [MaxLength(120)]
  public string Title { get; set; }
  public List<Menu> Menus { get; }
}

Menu类的Table和MaxLength属性同样能够选择。使用Column属性改造SQL类型(代码文件MenusWithDataAnnotations
/ Menu.cs):

[Table("Menus", Schema ="mc")]
public class Menu
{
  public int MenuId { get; set; }
  [MaxLength(50)]
  public string Text { get; set; }
  [Column(TypeName ="Money")]
  public decimal Price { get; set; }
  public int MenuCardId { get; set; }
  public MenuCard MenuCard { get; set; }
}

选拔迁移创设数据库后得以见到结构名称下表的新名称,以及Title、Text
和 Price 字段中已更动的数据类型:

CREATE TABLE [mc].[MenuCards] (
  [MenuCardId] INT            IDENTITY (1, 1) NOT NULL,
  [Title]      NVARCHAR (120) NULL,
  CONSTRAINT [PK_MenuCard] PRIMARY KEY CLUSTERED ([MenuCardId] ASC)
);

CREATE TABLE [mc].[Menus] (
  [MenuId]     INT           IDENTITY (1, 1) NOT NULL,
  [MenuCardId] INT           NOT NULL,
  [Price]      MONEY         NOT NULL,
  [Text]       NVARCHAR (50) NULL,
  CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED ([MenuId] ASC),
  CONSTRAINT [FK_Menu_MenuCard_MenuCardId] FOREIGN KEY ([MenuCardId])
    REFERENCES [mc].[MenuCards] ([MenuCardId]) ON DELETE CASCADE
);

Fluent API  

潜移默化创建的表的另一种办法是使用Fluent
API中DbContext派生类的OnModelCreating方法。它的亮点是能够保持实体类型大概,而不加多此外性质,Fluent
API还提供了比使用品质越来越多的选项。 

以下代码片段展现了BooksContext类重写OnModelCreating方法。作为参数接收的ModelBuilder类提供了一部分方法,并定义了两种扩充方法。
HasDefaultSchema是中间三个恢宏方法,它将暗许结构选择于近日享有种类的模子。
Entity方法重返二个EntityTypeBuilder,使您能够自定义实体,比如将其映射到特定的表名和定义键和目录(代码文件Menus萨姆ple
/ MenusContext.cs):

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);

  modelBuilder.HasDefaultSchema("mc");

  modelBuilder.Entity<MenuCard>()
    .ToTable("MenuCards")
    .HasKey(c => c.MenuCardId);

  // etc.

  modelBuilder.Entity<Menu>()
    .ToTable("Menus")
    .HasKey(m => m.MenuId);

  // etc.
}

EntityTypeBuilder定义了一个Property方法来安顿属性。
Property方法重回PropertyBuilder,能够依次配置具备最大尺寸值,须要的安装和SQL类型的习性,并内定是不是应自动生成值(比如标志列):

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  // etc.

  modelBuilder.Entity<MenuCard>()
    .Property<int>(c => c.MenuCardId)
    .ValueGeneratedOnAdd();

  modelBuilder.Entity<MenuCard>()
    .Property<string>(c => c.Title)
    .HasMaxLength(50);

  modelBuilder.Entity<Menu>()
    .Property<int>(m => m.MenuId)
    .ValueGeneratedOnAdd();

  modelBuilder.Entity<Menu>()
.Property<string>(m => m.Text)
    .HasMaxLength(120);

  modelBuilder.Entity<Menu>()
    .Property<decimal>(m => m.Price)
    .HasColumnType("Money");

  // etc.
} 

EntityTypeBuilder定义映射方法去定义一对多映射。HasMany
结合 WithOne 方法定义了多Menus 和一个Menu Card 的投射。
HasMany须要与WithOne链接,即HasOne方法必要多个带WithMany或WithOne的链。链接
HasOne 和
WithMany定义了壹对多关系,链接HasOne与WithOne定义了一定的关系:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  // etc.

  modelBuilder.Entity<MenuCard>()
    .HasMany(c => c.Menus)
    .WithOne(m => m.MenuCard);
  modelBuilder.Entity<Menu>()
    .HasOne(m => m.MenuCard)
    .WithMany(c => c.Menus)
    .HasForeignKey(m => m.MenuCardId);
}

在OnModelCreating方法中开创映射之后能够创建如前所示的动员搬迁。

Fluent API  

潜移默化创立的表的另一种格局是应用Fluent
API中DbContext派生类的OnModelCreating方法。它的优点是足以保持实体类型大约,而不增多别的性质,Fluent
API还提供了比使用品质愈来愈多的选项。 

以下代码片段突显了BooksContext类重写OnModelCreating方法。作为参数接收的ModelBuilder类提供了部分方法,并定义了二种扩充方法。
HasDefaultSchema是内部3个增加方法,它将私下认可结构选用于方今全数项目标模子。
Entity方法重回多个EntityTypeBuilder,使你能够自定义实体,举个例子将其映射到一定的表名和定义键和目录(代码文件Menus萨姆ple
/ MenusContext.cs):

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);

  modelBuilder.HasDefaultSchema("mc");

  modelBuilder.Entity<MenuCard>()
    .ToTable("MenuCards")
    .HasKey(c => c.MenuCardId);

  // etc.

  modelBuilder.Entity<Menu>()
    .ToTable("Menus")
    .HasKey(m => m.MenuId);

  // etc.
}

EntityTypeBuilder定义了四个Property方法来布局属性。
Property方法重回PropertyBuilder,能够依次配置具备最大尺寸值,供给的安装和SQL类型的属性,并内定是不是应自动生成值(举例标志列):

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  // etc.

  modelBuilder.Entity<MenuCard>()
    .Property<int>(c => c.MenuCardId)
    .ValueGeneratedOnAdd();

  modelBuilder.Entity<MenuCard>()
    .Property<string>(c => c.Title)
    .HasMaxLength(50);

  modelBuilder.Entity<Menu>()
    .Property<int>(m => m.MenuId)
    .ValueGeneratedOnAdd();

  modelBuilder.Entity<Menu>()
.Property<string>(m => m.Text)
    .HasMaxLength(120);

  modelBuilder.Entity<Menu>()
    .Property<decimal>(m => m.Price)
    .HasColumnType("Money");

  // etc.
} 

EntityTypeBuilder定义映射方法去定义一对多映射。HasMany
结合 WithOne 方法定义了多Menus 和3个Menu Card 的投射。
HasMany要求与WithOne链接,即HasOne方法需要3个带WithMany或WithOne的链。链接
HasOne 和
WithMany定义了一对多关系,链接HasOne与WithOne定义了一定的涉及:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  // etc.

  modelBuilder.Entity<MenuCard>()
    .HasMany(c => c.Menus)
    .WithOne(m => m.MenuCard);
  modelBuilder.Entity<Menu>()
    .HasOne(m => m.MenuCard)
    .WithMany(c => c.Menus)
    .HasForeignKey(m => m.MenuCardId);
}

在OnModelCreating方法中开创映射之后能够创造如前所示的迁徙。

从数据库创制模型  

从模型能够创建数据库,相反从数据库也足以创制模型。 

要从SQL
Server数据库施行此操作,除了其余包,还必须将NuGet包加多到DNX项目中,EntityFramework.MicrosoftSqlServer.Design。然后能够在开垦人士命令指示符使用以下命令:

> dnx ef dbcontext scaffold 
"server=(localdb)\MSSQLLocalDb;database=SampleDatabase; trusted_connection=true""EntityFramework.MicrosoftSqlServer"

dbcontext命令能够从类型中列出DbContext对象,同时也创立DBContext对象。命令scaffold创立DbContext派生类以及模型类。
dnx ef dbcontext scaffold
要求三个须要的参数:数据库的接连字符串和选择的提供程序。后边所示的言辞中,在SQL
Server(localdb)\
MSSQLLocalDb上访问数据库萨姆pleDatabase。使用的提供程序是EntityFramework.MicrosoftSqlServer。这些NuGet包以及全部同样名称和设计后缀的NuGet包必须增添到项目中。 

运维此命令后,能够见见DbContext派生类以及改变的模子类型。暗中同意意况下,模型的安排使用fluent
API完结。但是也能够将其更动为利用提供-a选项的数码疏解。还是能够影响生成的左右文类名称以及出口目录。只需利用选择-h检查不一样的可用选项。

 

—————-未完待续

从数据库创造模型  

从模型能够创制数据库,相反从数据库也足以制造模型。 

要从SQL
Server数据库实施此操作,除了别的包,还非得将NuGet包增加到DNX项目中,EntityFramework.MicrosoftSqlServer.Design。然后能够在开采人士命令提醒符使用以下命令:

> dnx ef dbcontext scaffold 
"server=(localdb)\MSSQLLocalDb;database=SampleDatabase; trusted_connection=true""EntityFramework.MicrosoftSqlServer"

dbcontext命令能够从品类中列出DbContext对象,同时也开创DBContext对象。命令scaffold创建DbContext派生类以及模型类。
dnx ef dbcontext scaffold
供给多个必备的参数:数据库的连日字符串和利用的提供程序。前边所示的语句中,在SQL
Server(localdb)\
MSSQLLocalDb上访问数据库SampleDatabase。使用的提供程序是EntityFramework.MicrosoftSqlServer。那几个NuGet包以及具有同样名称和准备后缀的NuGet包必须加多到项目中。 

运行此命令后,能够看到DbContext派生类以及改造的模型类型。暗中同意景况下,模型的布署利用fluent
API完毕。然而也能够将其变动为利用提供-a选项的数据阐明。仍是能够影响生成的上下文类名称以及出口目录。只需使用选择-h检查不相同的可用选项。

 

—————-未完待续


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图