您的位置:新葡亰496net > 奥门新萄京娱乐场 > 新葡亰496net:尖端编制程序,多对多涉及的实体

新葡亰496net:尖端编制程序,多对多涉及的实体

发布时间:2019-06-20 12:38编辑:奥门新萄京娱乐场浏览(140)

    在付出涉及到数据库的主次时,常会遇上一先导规划的协会不能够满意需要必要再加多新字段或新表的境况,那时就须要打开数据库迁移。
    实现数据库迁移有大多样办法,从手动管理种种版本的ddl脚本,到落到实处团结的migrator,或是使用Entity Framework提供的Code First迁移功用。
    Entity Framework提供的动员搬迁成效能够满意大部分人的急需,但仍会存在难以分品种处理迁移代码和轻易并发"context has changed"错误的主题素材。

    **译文,个体原创,转载请表明出处(C# 6 与 .NET Core 1.0 高等编制程序 - 38 章 实体框架核心(上)),不对的位置接待建议与沟通。** 

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

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

    本章节译文分为上下篇,下篇见: C# 6 与 .NET Core 1.0 高档编制程序 - 38 章 实体框架宗旨(下)


    本章内容

    • 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 

    **译文,个人原创,转载请评释出处(C# 6 与 .NET Core 1.0 高端编制程序 - 38 章 实体框架主题(上)),不对的地点应接提议与沟通。** 

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

    附英文版最初的作品:Professional C# 6 and .NET Core 1.0 - 38 Entity Framework Core

    本章节译文分为上下篇,下篇见: C# 6 与 .NET Core 1.0 高档编制程序 - 38 章 实体框架宗旨(下)


    本章内容

    • 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上使用的不二秘籍。
    能够成功增添实体字段后,只需刷新网页就能够把改变应用到数据库。

    实体框架的野史

    实体框架是提供实体到关系的绚烂的框架。通过这种艺术,可以创建映射到数量库表的类型,使用LINQ创制数据库查询,创设和换代指标,并将它们写入数据库。 

    由此长此现在对Entity Framework的少些修改,最新的版本是三个全然的重写。一齐来看望Entity Framework的野史,以及重写的来由。

    • Entity Framework 1—Entity Framework的首先个版本未有希图好与.NET 3.5协作,但它高效就足以与.NET 3.5 SP1包容。另三个成品LINQ to SQL提供了一些好像的功力,且早已可用于.NET 3.5。 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 4 在.NET 4中相称,并且获得了主要创新,当中相当多来自LINQ到SQL的主见。由于变化十分的大,版本2和3已被跳过。那一个本子里增添了延期加载以博得访问属性的关系。在利用SQL数据定义语言(DDL)设计模型之后,能够成立数据库。未来接纳Entity Framework的四个模型是Database First或Model First。恐怕最根本的特征是帮忙轻便对象类(POCO),由此不再须要从基类EntityObject派生。

    乘势更新(举个例子Entity Framework 4.1,4.2),NuGet包扩大了额外的法力,因而能越来越快地抬高效果。 Entity Framework 4.1提供了Code First模型,个中用于定义映射的EDMX文件不再选拔。相反,全体的映照都接纳C#代码定义

    • 运用质量或Fluent API来定义的投射。

    Entity Framework 4.3日增了对搬迁的支撑。有了那或多或少,就能够利用C#代码定义数据库结构的更改。使用数据库从应用程序自动应用数据库更新。

    • Entity Framework 5—Entity Framework 5的NuGet包支持.NET 4.5和.NET 4应用程序。不过,Entity Framework 5的多多作用都可用于.NET 4.5。 Entity Framework依然基于.NET 4.5在系统上安装的类型。此版本的新增添效益是性质创新以及辅助新的SQL Server成效,比方空间数据类型。

    • Entity Framework 6—Entity Framework 6消除了Entity Framework 5的局地难题,当中一部分是设置在系统上的框架的一片段,一部分通过NuGet扩大提供。近年来Entity Framework的整整代码已移至NuGet包。为了不形成争执,使用了四个新的命名空间。将应用程序移植到新本兔时,必须改造命名空间。

    本书探讨Entity Framework的流行版本,Entity Framework Core 1.0。此版本是贰个删减旧的行为周到重写,不再接济CSDL,SSDL和MSL的XML文件映射,只帮忙Code First - 使用Entity Framework 4.1抬高的模型。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 1.0不完全补助Entity Framework 6提供的有着机能。随着时光的延迟,Entity Framework的新本子将提供越来越多职能,留意所利用的Entity Framework的本子。尽管接纳Entity Framework 6 许多精锐的理由,但在非Windows平台上选取ASP.NET Core 1.0、Entity Framework和通用Windows平台(UWP),以及非关全面据存款和储蓄,都急需采纳Entity Framework Core 1.0。 

    本章介绍Entity Framework Core 1.0。从三个轻巧的模型读取和SQL Server中写入新闻开头,稍后会介绍增添关系,在写入数据库时将介绍改动追踪器和争辩管理。利用搬迁成立和更改数据库结构是本章的另叁个关键部分。 

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

    实体框架的野史

    实体框架是提供实体到事关的绚烂的框架。通过这种方法,可以创立映射到数量库表的类型,使用LINQ成立数据库查询,成立和翻新目的,并将它们写入数据库。 

    经过经过了相当长的时间对Entity Framework的一丢丢修改,最新的版本是叁个通通的重写。一齐来看看Entity Framework的历史,以及重写的原由。

    • Entity Framework 1—Entity Framework的首先个版本没有计划好与.NET 3.5一双两好,但它高效就足以与.NET 3.5 SP1兼容。另多少个成品LINQ to SQL提供了有个别像样的效果,且早已可用于.NET 3.5。 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 4 在.NET 4中卓绝,并且获得了关键创新,在这之中许多来自LINQ到SQL的主见。由于变化相当大,版本2和3已被跳过。这么些版本里扩张了延期加载以赢得访问属性的涉嫌。在运用SQL数据定义语言(DDL)设计模型之后,能够创设数据库。现在使用Entity Framework的五个模型是Database First或Model First。大概最关键的特征是援助轻松对象类(POCO),由此不再供给从基类EntityObject派生。

    随着更新(比如Entity Framework 4.1,4.2),NuGet包扩展了附加的机能,因而能更加快地抬高效果。 Entity Framework 4.1提供了Code First模型,当中用于定义映射的EDMX文件不再利用。相反,全体的映射都利用C#代码定义

    • 行使质量或Fluent API来定义的照射。

    Entity Framework 4.3扩展了对搬迁的支撑。有了那一点,就可以利用C#代码定义数据库结构的变动。使用数据库从应用程序自动应用数据库更新。

    • Entity Framework 5—Entity Framework 5的NuGet包协助.NET 4.5和.NET 4应用程序。可是,Entity Framework 5的无数作用都可用于.NET 4.5。 Entity Framework还是基于.NET 4.5在系统上安装的种类。此版本的新增加效益是性质革新以及帮忙新的SQL Server作用,比方空间数据类型。

    • Entity Framework 6—Entity Framework 6缓和了Entity Framework 5的有的难题,在这之中一部分是设置在系统上的框架的一片段,一部分通过NuGet扩张提供。方今Entity Framework的整整代码已移至NuGet包。为了不产生冲突,使用了贰个新的命名空间。将应用程序移植到新本丑时,必须改造命名空间。

    本书研讨Entity Framework的前卫版本,Entity Framework Core 1.0。此版本是八个删减旧的表现全面重写,不再补助CSDL,SSDL和MSL的XML文件映射,只援助Code First - 使用Entity Framework 4.1加上的模子。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 1.0不完全补助Entity Framework 6提供的具有功效。随着时光的延迟,Entity Framework的新本子将提供越来越多职能,留意所使用的Entity Framework的本子。即便采用Entity Framework 6 许多强硬的理由,但在非Windows平台上利用ASP.NET Core 1.0、Entity Framework和通用Windows平台(UWP),以及非关全面据存储,都急需使用Entity Framework Core 1.0。 

    本章介绍Entity Framework Core 1.0。从二个轻松的模型读取和SQL Server中写入新闻早先,稍后会介绍加多关系,在写入数据库时将介绍更换追踪器和冲突管理。利用搬迁成立和退换数据库结构是本章的另二个首要部分。 

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

    [C#/.NET]Entity Framework(EF) Code First 多对多关系的实业增,删,改,查操作全程详细示例

    本文大家来学习一下在Entity Framework中央银行使Context删除多对多关系的实体是何等来落实的。大家将以一个现实的调整台小实例来精晓和读书整个达成Entity Framework 多对多涉及的实体删除的操作进程。

    落实全自动员搬迁移的思路

    数据库迁移须要钦定更换的一对,比方增加表和增进字段。
    而落到实处机关迁移需求自动生成那个改换的有的,具体来讲必要

    • 得到数据库现成的构造
    • 获取代码中幸存的布局
    • 对照结构之间的异样并转移迁移

    那多亏Entity Framework的Add-Migration(或dotnet ef migrations add)命令所做的业务,
    接下去我们将看如何不利用那类的吩咐,在NHibernate, Entity Framework和Entity Framework Core中达成机关的管理。

    实体框架简单介绍

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

    在首先个示范中,首先创设数据库。能够动用Visual Studio 二〇一四中的SQL Server对象能源处理器实行此操作。选取数据库实例(与Visual Studio一齐安装的(localdb) MSSQLLocalDB),单击树视图中的数据库节点,然后接纳“增加新数据库”。示例数据库唯有三个名字为Books的表。 

    慎选Books数据库中的表节点,然后选拔"增加新表"来成立表Books。使用图38.第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 二〇一六中的SQL Server对象财富管理器推行此操作。选用数据库实例(与Visual Studio一齐安装的(localdb) MSSQLLocalDB),单击树视图中的数据库节点,然后接纳“增多新数据库”。示例数据库只有三个名称为Books的表。 

    分选Books数据库中的表节点,然后选用"加多新表"来创建表Books。使用图38.第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
    )
    

    您将学习到

    • 怎么创制二个引用Entity Framework的项目;

    • 怎么着配置Entity Framework的数据库连接;

    • 哪些去掉Entity Framework Code First 生成的表名的复数;

    • 怎么通过EntityTypeConfiguartion<T>配置实体的Fluent API ;

    • 什么配置Entity Framework的实体多对多的涉及映射;

    • Entity Framework数据初始化;

    • 如何使用包管理工具调控台来扭转和翻新数据库;

    • 怎么删除Entity Framework中的多对多涉及的多寡。

    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
    

     新葡亰496net 1

    图 38.1新葡亰496net:尖端编制程序,多对多涉及的实体增。  

    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数据库的身体力行应用程序Book萨姆ple是二个调控台应用程序(Package)。此示例使用以下依赖项和命名空间:

      依赖项

    NETStandard.Library
    Microsoft.EntityFrameworkCore
    Microsoft.EntityFrameworkCore.SqlServer
    

       取名空间

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

     新葡亰496net 2

    图 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; }
    }
    

    本示例开辟情状

    • 操作系统:Windows 10

    • 开采工具及版本:Visual Studio 二零一五 Update 1

    • .NET Framework版本:.NET Framework 4.6

    • 程序输出格局:调节台应用程序

    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的迁移能够确定保证实体和数据库之间很强的一致性,不过使用不当会促成原来数据的不见,请务必做好数据库的按时备份。

    创造上下文 

    始建的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);
      }
    }
    

    概念连接字符串的另多少个抉择是采取重视注入,将要本章前面介绍。 

    创立上下文 

    创办的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);
      }
    }
    

    概念连接字符串的另贰个摘取是接纳注重注入,将在本章前边介绍。 

    先是步、成立项目并引用程序包

    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;
    }
    

    在举行第二步事先,还索要先判定连接的数据库是否关周密据库,
    因为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 每一次迁移都会 1
    • 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方法(代码文件Books萨姆ple / 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对象财富处理器查看写入到数据库的数量。

    1.1 创造项目

    先是,我们创设二个调节台应用程序,取名称叫:EFRemoveManyToMany德姆o,如下图:

    新葡亰496net 3

     

    新葡亰496net 4

    写在最后

    机动迁移数据库要是没有错选拔,能够加强项目中各种模块的独立性,减弱支出和配置的专门的工作量。
    只是因为不可能手动调节搬迁内容,有必然的受制和危险,须要明白好利用的ORM迁移的风味。

    从数据库读取

    从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'
    

    *注意 在第13章“语言集成查询”中详尽切磋了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提供了一个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'
    

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

    1.2 引用程序包

    跟着展开程序包处理工科具,安装必须的EntityFramework引用包,如下:

    新葡亰496net 5

     

    新葡亰496net 6

    写在最后的广告

    ZKWeb网页框架早就在实际项目中应用了那项技巧,近年来来看迁移部分依旧比较稳固的。
    那项本领最初是为着插件店肆而付出的,在下载安装插件未来无需重新编译主程序,无需执行其余迁移命令就会动用。
    脚下即便从未完成插件店肆,也收缩了累累平凡支出的做事。

    比如您有意思味,迎接出席ZKWeb调换群522083886共同钻探。

    革新记录

    只需退换已加载上下文的指标并调用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就能够轻易完毕立异记录(代码文件Books萨姆ple / 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语句删除全体而不是逐条删除记录。在第37章“ADO.NET”中解释了怎样产生这点。*

    摸底了何等增多、查询、更新和删除记录,本章将介绍幕后的机能,并选用Entity Framework进入高等场景。

    删除记录

    最后,让大家清理数据库并删除全体记录。能够由此查找全体记录并调用Remove或RemoveRange方法来安装上下文中要去除的对象的状态。然后调用SaveChangesAsync方法就可以从数据库中除去记录,DbContext会为各样要删减的靶子调用SQL Delete语句(代码文件Books萨姆ple / 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语句删除全数而不是逐条删除记录。在第37章“ADO.NET”中表达了怎么样完毕这或多或少。*

    叩问了如何增添、查询、更新和删除记录,本章将介绍幕后的意义,并行使Entity Framework进入高级场景。

    2.1 成立实体类

    安装好Entity Framework包之后 ,大家先创建本示例须求的多个实体对应的类:User和Role(都位于Model的文件夹下),如下:

    User.cs

     1 using System;
     2 using System.Collections.Generic;
     3 
     4 namespace EFRemoveManyToManyDemo.Model
     5 {
     6     public class User
     7     {
     8         public User()
     9         {
    10             Roles = new HashSet<Role>();
    11         }
    12         public int Id { get; set; }
    13         public string FirstName { get; set; }
    14         public string LastName { get; set; }
    15         public DateTime? CreatedOn { get; set; }
    16         public virtual ICollection<Role> Roles { get; set; }//多对多关系中两边都要写上ICollection
    17     }
    18 }
    

     

    Role.cs

     1 using System.Collections.Generic;
     2 
     3 namespace EFRemoveManyToManyDemo.Model
     4 {
     5     public class Role
     6     {
     7         public Role()
     8         {
     9             this.Users = new HashSet<User>();!!依赖注入中的构造器注入
    10         }
    11         public int Id { get; set; }
    12         public string Name { get; set; }
    13 
    14         public virtual ICollection<User> Users { get; set; }
    15         //多对多关系中两边都要写上ICollection
    16     }
    17 }
    

     

    选用正视注入  

    Entity Framework Core 1.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属性(代码文件Books山姆pleWithDI / BooksContext.cs):

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

    BooksService是选拔BooksContext的新类。BooksContext通过注入构造函数注入。方法AddBooksAsync和ReadBooks与上贰个演示中的那个艺术充裕相像,但他们运用BooksService类的上下文成员,而不是成立一个新的(代码文件Books萨姆pleWithDI / Books瑟维斯.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与上贰个示范是左近的功能(代码文件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();
    }
    

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

    *注意 在第31章“XAML应用程序的情势”中阅读有关重视注入和Microsoft.Framework.DependencyInjection包的更加的多音讯,还足以参见第40章“ASP.NET Core”和第41章“ ASP.NET MVC“。*

    采纳依赖注入  

    Entity Framework Core 1.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; }
    }
    

    BooksService是运用BooksContext的新类。BooksContext通过注入构造函数注入。方法AddBooksAsync和ReadBooks与上一个示范中的这个格局充裕相像,但她俩利用BooksService类的上下文成员,而不是成立叁个新的(代码文件BooksSampleWithDI / 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 方法中起先化。创立三个瑟维斯Collection实例,将BooksService类增多到此集聚中,并张开不经常生命周期管理。那样,每便请求该服务时都会实例化 ServiceCollection。对于注册Entity Framework和SQL Server,能够用扩张方法AddEntityFramework,AddSqlServer和AddDbContext。 AddDbContext方法必要一个Action委托作为参数,在那之中接收到一个DbContextOptionsBuilder参数。有了该选项参数,能够采纳UseSqlServer扩展方法配置上下文。这里用Entity Framework注册SQL Server与上几个示范是近乎的成效(代码文件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();
    }
    

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

    *注意 在第31章“XAML应用程序的方式”中读书有关正视注入和Microsoft.Framework.DependencyInjection包的更加多信息,还足以参见第40章“ASP.NET Core”和第41章“ ASP.NET MVC“。*

    2.2 配置Fluent API

    为了布置Fluent API,新建八个Mapping文件夹,再分别创造User的布署文件UserConfigurationMapping和Role的安顿文件RoleConfigurationMapping,如下:

    UserConfiguration.cs

    using EFRemoveManyToManyDemo.Model;
    using System.Data.Entity.ModelConfiguration;
    
    namespace EFRemoveManyToManyDemo.Mapping
    {
        public class UserConfigurationMapping : EntityTypeConfiguration<User>
        {
            public UserConfigurationMapping()
            {
                Property(x => x.FirstName).HasMaxLength(50).IsRequired();
                Property(x => x.LastName).HasMaxLength(50).IsRequired();
            }
        }
    }
    

     

    RoleConfigurationMapping.cs

     1 using EFRemoveManyToManyDemo.Model;
     2 using System.Data.Entity.ModelConfiguration;
     3 
     4 namespace EFRemoveManyToManyDemo.Mapping
     5 {
     6     public class RoleConfigurationMapping : EntityTypeConfiguration<Role>
     7     {
     8         public RoleConfigurationMapping()
     9         {
    10             HasKey(x => x.Id);
    11             Property(x => x.Name).HasMaxLength(50).IsRequired();
    12             HasMany(x => x.Users)
    13                 .WithMany(x => x.Roles)
    14                 .Map(m =>
    15                 {
    16                     m.MapLeftKey("RoleId");
    17                     m.MapRightKey("UserId");
    18                     m.ToTable("LNK_User_Role");
    19                 });
    20         }
    21     }
    22 }
    

     

    创设模型  

    本章的第三个示例映射单个表。第一个例子展现了创立表之间的关联。在本节中应用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
    

    2.3 创建Context类

    接下去,大家更创立四个名字为:ManyToManyRemoveContext的类,该类承袭至DbContext类,用于管理数据库的连天上下文和数据库开首化等的有的陈设和操作,如下:

    using EFRemoveManyToManyDemo.Mapping;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration.Conventions;
    
    namespace EFRemoveManyToManyDemo
    {
        public class ManyToManyRemoveContext : DbContext
        {
            public ManyToManyRemoveContext() : base("ManyToManyRemoveContext")
            {
    
            }
        }
    }
    

     

    创造关系

    让大家伊始创造二个模子。示例项目利用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;
    }
    

    该关系也得以从另三个角度访问,菜单能够应用MenuCard属性访问MenuCard。内定MenuCardId 属性去定义外键关系(代码文件MenusSample / 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(代码文件MenusSamples / 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属性轻巧定义(代码文件Menus萨姆ple / Menu卡德.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;
    }
    

    该关系也能够从另二个角度访问,菜单能够使用Menu卡德属性访问MenuCard。指定MenuCardId 属性去定义外键关系(代码文件MenusSample / 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);
      }
    }
    

    2.4 配置连接字符串

    再在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=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
      </configSections>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
      </startup>
      <connectionStrings>
        <add name="ManyToManyRemoveContext" connectionString="server=你的数据库服务器地址;database=ManyToManyRemoveDemo;uid=你的数据库登录名;pwd=密码" providerName="System.Data.SqlClient"/>
      </connectionStrings>
      <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
          <parameters>
            <parameter value="mssqllocaldb" />
          </parameters>
        </defaultConnectionFactory>
        <providers>
          <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
      </entityFramework>
    </configuration>
    

     

    使用.NET CLI进行搬迁

    要动用C#代码自动创制数据库,能够应用enet工具使用package dotnet-ef增加.NET CLI工具。此软件单肩包含用于为搬迁创建C#代码的吩咐。通过设置dotnet-ef NuGet包能够职分令可用。您能够通过从类型安顿文件(代码文件MenusSample / 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方法列出了成立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");
      }
    }
    

    注意 正在开始展览的各样退换都能够创制另一个搬迁。新搬迁仅定义从先前版本到新本子所需的改造。假若客户的数据库需求从随机早先年代的本子更新,迁移数据库时调用供给的搬迁。 

    在开荒进度中,也行不要求具备的动员搬迁,或然要求从项目中开创,因为可能未有该类有的时候气象的数据库存在。在这种气象下可以去除迁移并创办贰个不小的新搬迁。

    使用.NET CLI进行搬迁

    要选择C#代码自动创制数据库,能够动用enet工具使用package dotnet-ef扩大.NET CLI工具。此软件公文包含用于为搬迁创制C#代码的吩咐。通过设置dotnet-ef NuGet包能够职责令可用。您能够透过从类型布局文件(代码文件MenusSample / 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");
      }
    }
    

    注意 正在开始展览的各种改造都得以创设另二个搬迁。新搬迁仅定义从原先版本到新本子所需的改换。借使客户的数据库需求从随机先前时代的本子更新,迁移数据库时调用须求的迁移。 

    在支付进度中,也行不须要全数的迁徙,大概必要从项目中开创,因为只怕未有该类一时气象的数据仓库储存在。在这种状态下能够去除迁移并创立多少个相当的大的新搬迁。

    2.5 重写Context

    为了将大家刚刚写的Fluent API应用到相应的实体上,所以我们要求重写(override)DbContext的OnModelCreating方法,如下:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    
                modelBuilder.Configurations.Add(new UserConfigurationMapping());
                modelBuilder.Configurations.Add(new RoleConfigurationMapping());
            }
    

     

    其中

    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

      是将Entity Framework Code First在实业类生成对应表时去掉表名的复数用的。简单地说正是,默许情形下,Entity Framework Code First在由实体类生成对应表时的表名是复数情势的,举例本例的User和Role类,要是没有这句配置,在扭转表名的时候将会是Users和Roles那三个表名,反之,则是User和Role那五个表名。

    好了,上面贴出完整的ManyToManyRemoveContext.cs文件的代码:

     1 using EFRemoveManyToManyDemo.Mapping;
     2 using EFRemoveManyToManyDemo.Model;
     3 using System.Data.Entity;
     4 using System.Data.Entity.ModelConfiguration.Conventions;
     5 
     6 namespace EFRemoveManyToManyDemo
     7 {
     8     public class ManyToManyRemoveContext : DbContext
     9     {
    10         public ManyToManyRemoveContext() : base("ManyToManyRemoveContext")
    11         {
    12 
    13         }
    14 
    15         protected override void OnModelCreating(DbModelBuilder modelBuilder)
    16         {
    17             base.OnModelCreating(modelBuilder);
    18             modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    19 
    20             modelBuilder.Configurations.Add(new UserConfigurationMapping());
    21             modelBuilder.Configurations.Add(new RoleConfigurationMapping());
    22         }
    23 
    24         public DbSet<User> Users { get; set; }
    25         public DbSet<Role> Roles { get; set; }
    26     }
    27 }
    

     

    本文写到这里,关于Entity Framework的引用,实体类的扬言和Fluent API配置以及与数据库连接等操作都已成功了。接下来大家要做的是选拔Entity Framework所实体生成到安排好的数据库中。

    运用MSBuild实行搬迁  

    假诺您正在使用基于MSBuild的项目Entity Framework迁移而不是DNX,迁移命令是见仁见智的。使用完整框架调节台应用程序、WPF应用程序或ASP.NET 4.6项目项目,须要在NuGet包管理器调整高雄钦命迁移命令,而不是开拓职员命令提醒符。从Visual Studio通过 工具➪库管理器调控台➪包处理器调控台 运维包管理器调控台。

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

    > Add-Migration InitMenuCards
    

    创制贰个Migrations文件夹,其中含有如前所示的迁移类。

    成立数据库 

    随着迁移类型形成,能够成立数据库。 DbContext派生类MenusContext包罗四个重临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}");
      }
    }
    

    注意 只要数据仓库储存在可是八个较旧的布局版本,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表定义了Menu卡德Id,它是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 列的深浅能够从NVA宝马7系CHAPRADO(MAX)减小,SQL Server定义了可用于Price列的Money类型,并且组织名称能够从dbo退换。 Entity Framework提供了五个选拔从代码中实施这一个改换:数据申明和Fluent API,下边将斟酌。

    数码演说

    潜移默化生成的数据库的一种办法是向实体类型丰盛数据注释。能够动用Table属性更换表的称号。要改造结构名称,Table属性定义Schema属性。借使要为字符串类型内定差异的尺寸,能够应用MaxLength属性(代码文件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 和 普赖斯 字段中已更动的数据类型:

    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.6项目种类,须要在NuGet包管理器调整高雄钦命迁移命令,而不是开辟人士命令提醒符。从Visual Studio通过 工具➪库管理器调控台➪包管理器调整台 运行包管理器调整台。

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

    > Add-Migration InitMenuCards
    

    开创三个Migrations文件夹,当中包蕴如前所示的迁移类。

    成立数据库 

    乘机迁移类型产生,可以创设数据库。 DbContext派生类MenusContext包括三个赶回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}");
      }
    }
    

    注意 假使数据仓库储存在然则二个较旧的布局版本,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 列的深浅能够从NVA大切诺基CHA大切诺基(MAX)减小,SQL Server定义了可用来普赖斯列的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
    );
    

    其三步、应用Migration生成数据库

    在接下去的历程中,大家会用到包管控台(Package Manager Console)和四个指令:

    Fluent API  

    影响创设的表的另一种格局是运用Fluent API中DbContext派生类的OnModelCreating方法。它的优点是能够保证实体类型大致,而不增多别的性质,Fluent API还提供了比使用质量更加的多的选项。 

    以下代码片段突显了BooksContext类重写OnModelCreating方法。作为参数接收的ModelBuilder类提供了部分方法,并定义了两种扩大方法。 HasDefaultSchema是内部三个扩大方法,它将暗许结构选用于最近颇具项目标模子。 Entity方法重返五个EntityTypeBuilder,令你可以自定义实体,比如将其映射到一定的表名和定义键和目录(代码文件MenusSample / 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是内部贰个增添方法,它将暗中同意结构采纳于方今颇具类型的模子。 Entity方法重返一个EntityTypeBuilder,令你能够自定义实体,比如将其映射到一定的表名和定义键和目录(代码文件MenusSample / 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方法中创制映射之后方可创设如前所示的搬迁。

    3.1 Enable-Migrations

    一声令下使用方法如下图:

    新葡亰496net 7

     

    新葡亰496net 8

    运行以上命令后,Entity Framework会自动在大家的花色中创制二个名称叫Migrations的文本夹,同期生成三个Configuartion.cs的安顿文件。那时的连串结构大意上是那般的:

    新葡亰496net 9

     

    新葡亰496net 10

    转移好Configuration.cs的公文大家再作多少的先导化,如下:

    namespace EFRemoveManyToManyDemo.Migrations
    {
        using Model;
        using System;
        using System.Collections.Generic;
        using System.Data.Entity.Migrations;
        using System.Linq;
        internal sealed class Configuration : DbMigrationsConfiguration<ManyToManyRemoveContext>
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }
    
            protected override void Seed(ManyToManyRemoveContext context)
            {
                var roles = new List<Role> {
                    new Role{ Id=1,Name="超级管理员" },
                    new Role{ Id=2,Name="管理员" },
                    new Role{ Id=3,Name="一般用户" }
                };
    
                var users = new List<User> {
                    new User {Id=1,FirstName="Kobe",LastName="Bryant",CreatedOn=DateTime.Now,Roles=roles },
                     new User {Id=2,FirstName="Chris",LastName="Paul",CreatedOn=DateTime.Now,Roles=roles.Where(x=>x.Id==2).ToList() },
                     new User {Id=3,FirstName="Jerimy",LastName="Lin",CreatedOn=DateTime.Now,Roles=roles.Take(2).ToList() }
                };
            }
        }
    }
    

     

    做到第三个指令和数据初阶化配置后,大家开始展览第二个指令。

    从数据库创制模型  

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

    要从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检查分裂的可用选项。

     

    ----------------未完待续

    从数据库创设模型  

    从模型能够创立数据库,相反从数据库也得以创立模型。 

    要从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检查分歧的可用选项。

     

    ----------------未完待续

    3.2 Add-Migration Init -Verbose

    推行此命令后,会在Migrations的公文夹中自动生成三个形如:时间戳_Init.cs的数据迁移文件,如本例生成的是二〇一四12040507219_Init.cs那样一个文书名,个中Init是大家钦命的此番数据迁移的本子名称,文件中的内容如下:

     1 namespace EFRemoveManyToManyDemo.Migrations
     2 {
     3     using System;
     4     using System.Data.Entity.Migrations;
     5     
     6     public partial class Init : DbMigration
     7     {
     8         public override void Up()
     9         {
    10             CreateTable(
    11                 "dbo.Role",
    12                 c => new
    13                     {
    14                         Id = c.Int(nullable: false, identity: true),
    15                         Name = c.String(nullable: false, maxLength: 50),
    16                     })
    17                 .PrimaryKey(t => t.Id);
    18             
    19             CreateTable(
    20                 "dbo.User",
    21                 c => new
    22                     {
    23                         Id = c.Int(nullable: false, identity: true),
    24                         FirstName = c.String(nullable: false, maxLength: 50),
    25                         LastName = c.String(nullable: false, maxLength: 50),
    26                         CreatedOn = c.DateTime(),
    27                     })
    28                 .PrimaryKey(t => t.Id);
    29             
    30             CreateTable(
    31                 "dbo.LNK_User_Role",
    32                 c => new
    33                     {
    34                         RoleId = c.Int(nullable: false),
    35                         UserId = c.Int(nullable: false),
    36                     })
    37                 .PrimaryKey(t => new { t.RoleId, t.UserId })
    38                 .ForeignKey("dbo.Role", t => t.RoleId, cascadeDelete: true)
    39                 .ForeignKey("dbo.User", t => t.UserId, cascadeDelete: true)
    40                 .Index(t => t.RoleId)
    41                 .Index(t => t.UserId);
    42             
    43         }
    44         
    45         public override void Down()
    46         {
    47             DropForeignKey("dbo.LNK_User_Role", "UserId", "dbo.User");
    48             DropForeignKey("dbo.LNK_User_Role", "RoleId", "dbo.Role");
    49             DropIndex("dbo.LNK_User_Role", new[] { "UserId" });
    50             DropIndex("dbo.LNK_User_Role", new[] { "RoleId" });
    51             DropTable("dbo.LNK_User_Role");
    52             DropTable("dbo.User");
    53             DropTable("dbo.Role");
    54         }
    55     }
    56 }
    

     

    大家得以经过那么些文件中的内容来看,有Up()和Down()那七个点子,Up()方法要实行的实在正是此番数据迁移要对数码举行的操作,而Down()方法则是在后头我们只要要退回到此版本应该实施的操作。

    由此上述几个指令,如你心急地要去数据库管理工科具中查看有二个称呼:ManyToManyRemove德姆o的数据库是或不是已生成,那么很不满地告诉您,还平素不。那时,大家还得实践最终三个命令来生成数据库和实体对应的表。

    3.3 Update-Database -Verbose

    执行以上命令,大家那儿再张开数据库管理工具。没有错ManyToManyRemove德姆o就在这里。再查看表是或不是成功转移呢,再检查一下表中是或不是有大家初步化的数据吧,没有错,这么些都以能够部分。怎么着,惊奇啊,欢呼吧,我们成功了!!!

    新葡亰496net 11

     

    新葡亰496net 12

    但还没完,请先过来平静,那还只是三个始发。Entity Framework还足以做得更加多,大家须求上学的也还会有非常多,编制程序的征途平素就不是一步到位的,得有个经过。一步一步往下看吗。

    第四步、增、删、改、查操作

    4.1 查询数据示例

    张开大家项目标Program.cs文件。首先,大家来查询(Query)一下数据库中的数据,如下:

     1 static void Main(string[] args)
     2         {
     3             Query();
     4             ReadKey();
     5         }
     6 
     7         static void Query()
     8         {
     9             using (var cxt = new ManyToManyRemoveContext())
    10             {
    11                 var users = cxt.Users.ToList();
    12                 users.ForEach(x =>
    13                 {
    14                     WriteLine("User First Name:{0},Last Name:{1},Create On:{2}n |__Roles:{3}", x.FirstName, x.LastName, x.CreatedOn, string.Join(",", x.Roles.Select(r => r.Name)));
    15                 });
    16             }
    17         }
    

     

    运行结果如图:

    新葡亰496net 13

     

    新葡亰496net 14

    4.2 更新数据示例

    再来更新一条数据库中的数据如何,如下:

     1  static void Main(string[] args)
     2         {
     3             Update();
     4             Query();
     5             ReadKey();
     6         }
     7 
     8 static void Query()
     9         {
    10             using (var cxt = new ManyToManyRemoveContext())
    11             {
    12                 var users = cxt.Users.ToList();
    13                 users.ForEach(x =>
    14                 {
    15                     WriteLine("User First Name:{0},Last Name:{1},Create On:{2}n |__Roles:{3}", x.FirstName, x.LastName, x.CreatedOn, string.Join(",", x.Roles.Select(r => r.Name)));
    16                 });
    17             }
    18         }
    19 
    20 static void Update()
    21         {
    22             using (var cxt = new ManyToManyRemoveContext())
    23             {
    24                 var user = cxt.Users.FirstOrDefault(x=>x.Id==3);
    25                 user.FirstName = "ShuHao";
    26                 cxt.SaveChanges();
    27             }
    28         }
    

     

    运维结果如大家所料,如图:

    新葡亰496net 15

     

    新葡亰496net 16

    4.3 删除数据示例

    Id为3的User的FirstName已经从数据库更新了。同样的,大家要形成删除操作也正如简,如下:

    1  static void Remove()
    2         {
    3             using (var cxt = new ManyToManyRemoveContext())
    4             {
    5                 var user = cxt.Users.FirstOrDefault(x=>x.Id==2);
    6                 cxt.Users.Remove(user);
    7                 cxt.SaveChanges();
    8             }
    9         }
    

     

    4.4 新增加多少示例

    就不再贴图了。最后是加上操作,向User表加多八个用户并分配叁个Id为1的角色,代码如下:

     1 static void Add()
     2         {
     3             List<Role> roles;
     4             using (var cxt = new ManyToManyRemoveContext())
     5             {
     6                 roles = cxt.Roles.ToList();
     7                 cxt.Users.Add(new User
     8                 {
     9                     Id = 4,
    10                     FirstName = "Console",
    11                     LastName = "App",
    12                     CreatedOn = DateTime.Now,
    13                     Roles = roles.Where(x => x.Id == 1).ToList()
    14                 });
    15             }
    16         }
    

     

    4.5 删除多对绝大大多据的演示

    好了,以上是对User(用户实体)进行轻易的增、删、改、查的操作,那么大家要贯彻多对多的去除操作呢?也正是剔除用户的还要删除其对应的剧中人物,达成的代码如下:

     1 static void RemoveManyToMany()
     2         {
     3             using (var cxt = new ManyToManyRemoveContext())
     4             {
     5                 var user = cxt.Users.FirstOrDefault(x => x.Id == 1);
     6                 var roles = new List<Role>();
     7                 roles.AddRange(user.Roles.Select(x => x));
     8                 foreach (var role in roles)
     9                 {
    10                     user.Roles.Remove(role);
    11                 }
    12                 cxt.Users.Remove(user);
    13                 cxt.SaveChanges();
    14             }
    15         }
    

     

    运作结果如图:

    新葡亰496net 17

     

    新葡亰496net 18

    一体化示例代码及下载地址

    好了,最终把Program.cs那么些测试文件贴上来,供参考:

     1 using EFRemoveManyToManyDemo.Model;
     2 using System;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using static System.Console;
     6 
     7 namespace EFRemoveManyToManyDemo
     8 {
     9     public class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             //Update();
    14             WriteLine("Before many to many removed");
    15             Query();
    16             RemoveManyToMany();
    17             WriteLine("After many to many removed");
    18             Query();
    19             ReadKey();
    20         }
    21 
    22         static void Query()
    23         {
    24             using (var cxt = new ManyToManyRemoveContext())
    25             {
    26                 var users = cxt.Users.ToList();
    27                 users.ForEach(x =>
    28                 {
    29                     WriteLine("User First Name:{0},Last Name:{1},Create On:{2}n |__Roles:{3}", x.FirstName, x.LastName, x.CreatedOn, string.Join(",", x.Roles.Select(r => r.Name)));
    30                 });
    31             }
    32         }
    33 
    34         static void Add()
    35         {
    36             List<Role> roles;
    37             using (var cxt = new ManyToManyRemoveContext())
    38             {
    39                 roles = cxt.Roles.ToList();
    40                 cxt.Users.Add(new User
    41                 {
    42                     Id = 4,
    43                     FirstName = "Console",
    44                     LastName = "App",
    45                     CreatedOn = DateTime.Now,
    46                     Roles = roles.Where(x => x.Id == 1).ToList()
    47                 });
    48             }
    49         }
    50 
    51         static void Update()
    52         {
    53             using (var cxt = new ManyToManyRemoveContext())
    54             {
    55                 var user = cxt.Users.FirstOrDefault(x => x.Id == 3);
    56                 user.FirstName = "ShuHao";
    57                 cxt.SaveChanges();
    58             }
    59         }
    60 
    61         static void Remove()
    62         {
    63             using (var cxt = new ManyToManyRemoveContext())
    64             {
    65                 var user = cxt.Users.FirstOrDefault(x => x.Id == 2);
    66                 cxt.Users.Remove(user);
    67                 cxt.SaveChanges();
    68             }
    69         }
    70 
    71         static void RemoveManyToMany()
    72         {
    73             using (var cxt = new ManyToManyRemoveContext())
    74             {
    75                 var user = cxt.Users.FirstOrDefault(x => x.Id == 1);
    76                 var roles = new List<Role>();
    77                 roles.AddRange(user.Roles.Select(x => x));
    78                 foreach (var role in roles)
    79                 {
    80                     user.Roles.Remove(role);
    81                 }
    82                 cxt.Users.Remove(user);
    83                 cxt.SaveChanges();
    84             }
    85         }
    86     }
    87 }
    

     

    本文由新葡亰496net发布于奥门新萄京娱乐场,转载请注明出处:新葡亰496net:尖端编制程序,多对多涉及的实体

    关键词: