尖端编制程序,使用HiLo生成主键

HiLo是在NHibernate中生成主键的一种方法,可是今后咱们能够在Entity
Framework Core中运用。所以在那篇内容中,小编将向您在介绍如何在Entity
Framework Core中动用HiLo生成主键。

始建立模型型  

本章的率先个示例映射单个表。第叁个例证呈现了创制表之间的关系。在本节中动用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

向HiLo运用到单个实体

地点的代码两个表共用一个HiLo系列。如果你只想针对二个一定的表,那么您能够采纳下边包车型大巴代码。

    modelbuilder.Entity<Category>().
            Property(o => o.CategoryID).ForSqlServerUseSequenceHiLo();

这段代码将制造贰个暗中同意名为“EntityFrameworkHiLoSequence”的新连串,因为未有一点点名名字。您也得以定义多少个HiLo系列。举个例子:

    protected override void OnModelCreating(ModelBuilder modelbuilder)
    {
        modelbuilder.ForSqlServerUseSequenceHiLo("DBSequenceHiLo");
        modelbuilder.Entity<Category>()
                .Property(o => o.CategoryID).ForSqlServerUseSequenceHiLo();
    }

在数据库中,将成立三个连串。Category实体将使用EntityFrameworkHiLoSequence序号,全数别的实体使用DBSequenceHiLo序列。

图片 1

从数据库读取

从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 Events窗口,能够见见发送到数据库的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。
*

什么是Hilo?

HiLo是High Low的简写,翻译成普通话叫高低位情势。

HiLo是由“Hi”和“Lo”两局地生成主键的一种格局。“Hi”部分来源数据库,“Lo”部分在内存中生成以创立独一值。请记住,“Lo”是贰个限制数字,如0-100。因而,当“Hi”部分用完“Lo”范围时,再度开始展览数据库调用以博取下三个“Hi数字”。之所以HiLo格局的独到之处在于你事先能够清楚主键的值,而不用每一次都与数库据爆发互相

小结有以下四点:

  1. “Hi”部分由数据库分配,七个冒出央求保管收获独一的连日值;
  2. 假使获得“Hi”部分,大家还亟需领悟“incrementSize”的值(“Lo”条指标数目);
    “Lo”取的限量:[0,incrementSize];
  3. 标志范围的公式是:(Hi – 1) * incrementSize) + 1(Hi –
    1) * incrementSize) + incrementSize)
  4. 当全部“Lo”值使用完时,要求再行从数据库中抽出三个新的“Hi”值,并将“Lo”部分重新恢复设置为0。

在那边演示在七个冒出事务中的例子,每一个业务插入五个实体:

图片 2

从数据库创立模型  

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

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

 

—————-未完待续

配置HiLo序列

ForSqlServerHasSequence庞大方法不可能更改开头值和增量值的选项。不过,有一种办法来定义那一个接纳。首先,使用HasSequence艺术定义系列的StartAtIncrementBy选料,然后再使用ForSqlServerUseSequenceHiLo()扩充方法,要保持体系的名号一致。比如:

    modelbuilder.HasSequence<int>("DBSequenceHiLo")
                      .StartsAt(1000).IncrementsBy(5);
    modelbuilder.ForSqlServerUseSequenceHiLo("DBSequenceHiLo");

在这种状态下,生成DBSequenceHiLo的剧本如下。

CREATE SEQUENCE [dbo].[DBSequenceHiLo] 
 AS [int]
 START WITH 1000
 INCREMENT BY 5
 MINVALUE -2147483648
 MAXVALUE 2147483647
 CACHE 
GO

故此当我们实践同一的代码插入3个Category实业,那么主键的值将从一千从头。

图片 3

何况由于IncrementBy慎选设置为“5”,所以当在前后文中增多第6个插入时,将进行数据库调用以获取下一个种类值。以下是插入3个Category实业然后插入3个的Product实体时SQL
Server
profiler的显示屏截图,您能够看看数据库调用获取体系的下贰个值的次数是2次。
图片 4

如果你对在Entity Framework
Core中采纳HiLo生成主键感兴趣,不防自个儿入手测量试验一下。

参谋资料:

删除记录

最后,让我们清理数据库并删除全体记录。能够通过找寻全部记录并调用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步向高等场景。

Sql Server 序列

在EF Core中动用HiLo生成主键,大家还亟需理解Sql
Server中贰个概念序列(Sequence)

队列是在SQL Server
2013中引入的(但是Oracle很已经已经落到实处了http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_6015.htm)。类别是用户定义的对象,它依照创立的属性生成一多种数值。它与
Identity 列相似,但它们中间有许多区别之处。比方,

  • 队列用于转移数据库范围的连串号;
  • 队列不与二个表相关联,您能够将其与五个表相关联;
  • 它能够用来插入语句来插入标记值,也足以在T-SQL脚本中运用。

创立体系示例的SQL语句:

Create Sequence [dbo].[Sequence_Test] 
As [BigInt]         --整数类型
Start With 1        --起始值
Increment By 1      --增量值
MinValue 1          --最小值
MaxValue 9999999    --最大值
Cycle               --达到最值循环 [ CYCLE | NO CYCLE ]
Cache  5;           --每次取出5个值缓存使用 [ CACHE [<常量>] | NO CACHE ]

使用示例:

Create Table #T(Id BigInt Primary Key,[Time] DateTime);

Insert Into #T
            ( Id , Time )
Values      ( NEXT VALUE FOR [dbo].[Sequence_Test] , -- Id - bigint
              GetDate()  -- Time - datetime
              )
Go 10


Select * From #T

询问结果:

Id Time
1 2017-11-23 16:46:50.613
2 2017-11-23 16:46:50.643
3 2017-11-23 16:46:50.667
4 2017-11-23 16:46:50.677
5 2017-11-23 16:46:50.687
6 2017-11-23 16:46:50.697
7 2017-11-23 16:46:50.707
8 2017-11-23 16:46:50.717
9 2017-11-23 16:46:50.730
10 2017-11-23 16:46:50.740

关于种类越来越多的剧情,能够查阅如下质感:

始建模型 

用于访谈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

 图片 5


38.1
  

Book类是叁个简练的实体类型,它定义了八个属性。
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; }
}

动用HiLo生成主键

让我们看看怎么着利用HiLo在Entity Framework Core中生成主键。

为了演示,大家成立了四个从未涉及的实体。

    public class Category
    {
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }
    }

    public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
    }

请记住,EF Core按常规配置一个名叫Id<type
name>Id
用作实体的主键属性。今后大家须要创建我们的DBContext,在此地我们成立SampleDBContext.cs类:

public class SampleDBContext : DbContext
{
    public SampleDBContext()
    {
        Database.EnsureDeleted();
        Database.EnsureCreated();
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionbuilder)
    {
            var sqlConnectionStringBuilder = new SqlConnectionStringBuilder {
                DataSource = "****",
                InitialCatalog = "EFSampleDB",
                UserID = "sa",
                Password = "***"
            };
            optionsBuilder.UseSqlServer(sqlConnectionStringBuilder.ConnectionString);

    }

    protected override void OnModelCreating(ModelBuilder modelbuilder)
    {
        modelbuilder.ForSqlServerUseSequenceHiLo("DBSequenceHiLo");
    }

    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}
  • SampleDBContext构造函数初叶化数据库,类型于EF
    6中的DropCreateDatabaseAlways
  • OnConfiguring() 方法用于配置数据库链接字符串;
  • OnModelCreating方法用于定义实人体模型型。要定义HiLo连串,请使用ForSqlServerUseSequenceHiLo扩大方法。您供给提供类别的称呼。

运维应用程序,您应该在创造“EFSampleDB”数据库中见到Product表、Category表和DBSequenceHiLo序列。

图片 6

以下是创办DBSequenceHiLo的脚本。

Create Sequence [dbo].[DBSequenceHiLo] 
 As [BigInt]
 Start With 1
 Increment By 10
 MinValue -9223372036854775808
 MaxValue 9223372036854775807
 Cache 
Go

正如您所看到的,它从1从头,递增是10。

今昔向数据库中增加一些数额。以下代码首先加多3个Category实业和调用SaveChanges(),然后增加3个Product实体并调用SaveChanges()

    using (var dataContext = new SampleDBContext())
    {
        dataContext.Categories.Add(new Category() { CategoryName = "Clothing" });
        dataContext.Categories.Add(new Category() { CategoryName = "Footwear" });
        dataContext.Categories.Add(new Category() { CategoryName = "Accessories" });
        dataContext.SaveChanges();
        dataContext.Products.Add(new Product() { ProductName = "TShirts" });
        dataContext.Products.Add(new Product() { ProductName = "Shirts" });
        dataContext.Products.Add(new Product() { ProductName = "Causal Shoes" });
        dataContext.SaveChanges();
    }

当这几个代码第壹次被实践,Clothing
实体通过Add主意扩展到DBContext时,就能够向数据库调用获取连串的值,大家也足以因此SQL
Server Profiler来表明它。
图片 7

次调用dataContext.SaveChanges()时,3个Category实业将被保存。查看实行的SQL语句。主键值已经被转移,连串值的收获也只实行了一回。
图片 8

就算插入3个Product实体,连串值也不会从数据库中收获。唯有当插入10条记下(Lo部分耗尽)时,才会向数据库调用获得下一个(Hi部分)连串值。

成立关系

让大家开始创办八个模型。示例项目选拔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属性访谈Menu卡德。指定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);
  }
}

动用正视注入  

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属性(代码文件Books萨姆pleWithDI
/ 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
方法中伊始化。创造二个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; }

服务的初始化以及Books瑟维斯的运用是从Main方法成功的。通过调用I瑟维斯Provider的Get瑟维斯方法来寻觅BooksService(代码文件BooksSampleWithDI
/ 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“。*

实体框架简要介绍

先是个示范使用单个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
)

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 卡德 的照射。
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方法中创设映射之后方可创设如前所示的搬迁。

创建上下文 

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

概念连接字符串的另二个接纳是采用注重注入,将在本章后边介绍。 

写入数据库

当今已成立了有Books表的数据库,也定义了模型和前后文类,然后可以用数码填充表。创设AddBookAsync方法将Book对象增加到数据库。首先,BooksContext对象被实例化,这里运用using语句确认保证数据库连接关闭。使用Add方法将对象增多到上下文之后,实体被写入调用SaveChangesAsync的数据库(代码文件Books萨姆ple
/ 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对象资源管理器查看写入到数据库的数目。

实业框架的野史

实体框架是提供实体到事关的绚烂的框架。通过这种方法,能够成立映射到数量库表的花色,使用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

使用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删除数据库。以下代码片段创制数据库(纵然它不设有)(代码文件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。基于暗中认可约定,表与实体类型是一律的称谓。另一个预定用于创设主键:Menu卡德Id列会被定义为主键,因为属性名以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 列的深浅能够从NVARCHA翼虎(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
);

**译文,个体原创,转发请评释出处(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 

使用.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,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");
  }
}

注意 正在拓展的各类改造都得以创建另三个搬迁。新搬迁仅定义从原先版本到新本子所需的改造。假设客户的数据库需求从随机中期的本子更新,迁移数据库时调用供给的搬迁。 

在支付进度中,也行不供给全体的动员搬迁,大概须求从品种中开创,因为大概没有该类有的时候气象的数据仓库储存在。在这种意况下能够去除迁移并创办三个相当的大的新搬迁。

创新记录

只需改变已加载上下文的目的并调用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();
}