Entity Framework Core 使用HiLo生成主键
2017-11-27 07:28
543 查看
HiLo是在NHibernate中生成主键的一种方式,不过现在我们可以在Entity Framework Core中使用。所以在这篇内容中,我将向您在介绍如何在Entity Framework Core中使用HiLo生成主键。
HiLo是由“Hi”和“Lo”两部分生成主键的一种模式。“Hi”部分来自数据库,“Lo”部分在内存中生成以创建唯一值。请记住,“Lo”是一个范围数字,如0-100。因此,当“Hi”部分用完“Lo”范围时,再次进行数据库调用以获得下一个“Hi数字”。所以HiLo模式的优点在于您预先可以知道主键的值,而不用每次都与数库据发生交互。
总结有以下四点:
“Hi”部分由数据库分配,两个并发请求保证得到唯一的连续值;
一旦获取“Hi”部分,我们还需要知道“incrementSize”的值(“Lo”条目的数量);
“Lo”取的范围:[0,incrementSize];
标识范围的公式是:(Hi - 1) * incrementSize) + 1 到 (Hi - 1) * incrementSize) + incrementSize)
当所有“Lo”值使用完时,需要重新从数据库中取出一个新的“Hi”值,并将“Lo”部分重置为0。
在这里演示在两个并发事务中的例子,每个事务插入多个实体:
序列是在SQL Server 2012中引入的(不过Oracle很早就已经实现了http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_6015.htm)。序列是用户定义的对象,它根据创建的属性生成一系列数值。它与 Identity 列相似,但它们之间有很多不同之处。例如,
序列用于生成数据库范围的序列号;
序列不与一个表相关联,您可以将其与多个表相关联;
它可以用于插入语句来插入标识值,也可以在T-SQL脚本中使用。
创建序列示例的SQL语句:
使用示例:
查询结果:
关于序列更多的内容,可以查阅如下资料:
http://www.cnblogs.com/CareySon/archive/2012/03/12/2391581.html
http://www.cnblogs.com/dotnet261010/p/7082852.html
http://sqlhints.com/2015/08/01/difference-between-sequence-and-identity-in-sql-server/
https://raresql.com/2012/05/01/difference-between-identity-and-sequence/
为了演示,我们创建了两个没有关系的实体。
请记住,EF Core按惯例配置一个名为Id或<type name>Id作为实体的主键属性。现在我们需要创建我们的
在
运行应用程序,您应该在创建“EFSampleDB”数据库中看到
以下是创建
正如你所看到的,它从1开始,递增是10。
现在向数据库中添加一些数据。以下代码首先添加3个
当这个代码第一次被执行,Clothing 实体通过
次调用
即使插入3个
这段代码将创建一个默认名称为“EntityFrameworkHiLoSequence”的新序列,因为没有指定名字。您也可以定义多个HiLo序列。例如:
在数据库中,将创建两个序列。
在这种情况下,生成
所以当我们执行相同的代码插入3个
而且由于
如果您对在Entity Framework Core中使用HiLo生成主键感兴趣,不防自己动手测试一下。
参考资料:
https://vladmihalcea.com/2014/06/23/the-hilo-algorithm/
http://www.talkingdotnet.com/use-hilo-to-generate-keys-with-entity-framework-core/
#cnblogs_post_body.cnblogs-markdown p img { max-width: 95%; }
什么是Hilo?
HiLo是High Low的简写,翻译成中文叫高低位模式。HiLo是由“Hi”和“Lo”两部分生成主键的一种模式。“Hi”部分来自数据库,“Lo”部分在内存中生成以创建唯一值。请记住,“Lo”是一个范围数字,如0-100。因此,当“Hi”部分用完“Lo”范围时,再次进行数据库调用以获得下一个“Hi数字”。所以HiLo模式的优点在于您预先可以知道主键的值,而不用每次都与数库据发生交互。
总结有以下四点:
“Hi”部分由数据库分配,两个并发请求保证得到唯一的连续值;
一旦获取“Hi”部分,我们还需要知道“incrementSize”的值(“Lo”条目的数量);
“Lo”取的范围:[0,incrementSize];
标识范围的公式是:(Hi - 1) * incrementSize) + 1 到 (Hi - 1) * incrementSize) + incrementSize)
当所有“Lo”值使用完时,需要重新从数据库中取出一个新的“Hi”值,并将“Lo”部分重置为0。
在这里演示在两个并发事务中的例子,每个事务插入多个实体:
Sql Server 序列
在EF Core中使用HiLo生成主键,我们还需要了解Sql Server中一个概念序列(Sequence)。序列是在SQL Server 2012中引入的(不过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 |
http://www.cnblogs.com/CareySon/archive/2012/03/12/2391581.html
http://www.cnblogs.com/dotnet261010/p/7082852.html
http://sqlhints.com/2015/08/01/difference-between-sequence-and-identity-in-sql-server/
https://raresql.com/2012/05/01/difference-between-identity-and-sequence/
使用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序列。
以下是创建
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来验证它。
次调用
dataContext.SaveChanges()时,3个
Category实体将被保存。查看执行的SQL语句。主键值已经被生成,序列值的获取也只执行了一次。
即使插入3个
Product实体,序列值也不会从数据库中获取。只有当插入10条记录(Lo部分耗尽)时,才会向数据库调用获得下一个(Hi部分)序列值。
向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序列。
配置HiLo序列
ForSqlServerHasSequence扩展方法不能更改起始值和增量值的选项。但是,有一种方法来定义这些选项。首先,使用
HasSequence方法定义序列的
StartAt和
IncrementBy选项,然后再使用
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实体,那么主键的值将从1000开始。
而且由于
IncrementBy选项设置为“5”,所以当在上下文中添加第6个插入时,将进行数据库调用以获得下一个序列值。以下是插入3个
Category实体然后插入3个的
Product实体时SQL Server profiler的屏幕截图,您可以看到数据库调用获取序列的下一个值的次数是2次。
如果您对在Entity Framework Core中使用HiLo生成主键感兴趣,不防自己动手测试一下。
参考资料:
https://vladmihalcea.com/2014/06/23/the-hilo-algorithm/
http://www.talkingdotnet.com/use-hilo-to-generate-keys-with-entity-framework-core/
#cnblogs_post_body.cnblogs-markdown p img { max-width: 95%; }
相关文章推荐
- Entity Framework Core 使用HiLo生成主键
- [UWP]在UWP中使用EntityFrameworkCore + SQLite
- 在Apworks数据服务中使用基于Entity Framework Core的仓储(Repository)实现
- Entity Framework Core 2.0 使用代码进行自动迁移
- Asp.net Core中使用Entity Framework Core CodeFirst
- Entity Framework Core 生成跟踪列
- UWP: 在 UWP 中使用 Entity Framework Core 操作 SQLite 数据库
- EntityFrameworkCore初步使用
- ABP .Net Core Entity Framework迁移使用MySql数据库
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
- 使用 Entity Framework Core 时,通过代码自动 Migration
- (摘)Entity Framework Core 2.1带来更好的SQL语句生成方案
- EntityFrameworkCore使用Migrations自动更新数据库
- Entity Framework Core 2.0 使用入门
- ADO.NET Entity Framework 如何:使用 EdmGen.exe 生成模型和映射文件
- .Net Core 2.0生态(4):Entity Framework Core 2.0 特性介绍和使用指南
- Entity Framework Core 使用体会
- ADO.NET Entity Framework 如何:使用 EdmGen.exe 生成对象层代码
- 在Apworks数据服务中使用基于Entity Framework Core的仓储(Repository)实现
- 尝试.Net Core—使用.Net Core + Entity FrameWork Core构建WebAPI(一)