Entity Framework Core 使用HiLo生成主键
HiLo是在NHibernate中生成主键的一种方式,不过现在我们可以在Entity Framework Core中使用。所以在这篇内容中,我将向您在介绍如何在Entity Framework Core中使用HiLo生成主键。
什么是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生成主键的更多相关文章
- Entity Framework Core 2.0 中使用LIKE 操作符
Entity Framework Core 2.0 中使用LIKE 操作符 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译 ...
- Mysql EF 触发器生成主键id 存储区更新、插入或删除语句影响到了意外的行数(0)。实体在加载后可能被修改或删除。刷新 ObjectStateManager 项 ;System.Data.Entity.Infrastructure.DbUpdateConcurrencyException
http://stackoverflow.com/questions/24725261/how-to-use-a-custom-identity-column-in-sql-with-entity-f ...
- Entity Framework Core生成的存储过程在MySQL中需要进行处理及PMC中的常用命令
在使用Entity Framework Core生成MySQL数据库脚本,对于生成的存储过程,在执行的过程中出现错误,需要在存储过程前面添加 delimiter // 附:可以使用Visual Stu ...
- Entity Framework Core 生成跟踪列
本文翻译自<Entity Framework Core: Generate tracking columns>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 注意:我使用的是 ...
- Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 更新关系数据
Updating related data¶ 7 of 7 people found this helpful The Contoso University sample web applicatio ...
- Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 读取关系数据
Reading related data¶ 9 of 9 people found this helpful The Contoso University sample web application ...
- Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 创建复杂数据模型
Creating a complex data model 创建复杂数据模型 8 of 9 people found this helpful The Contoso University sampl ...
- Working with Data » 使用Visual Studio开发ASP.NET Core MVC and Entity Framework Core初学者教程
原文地址:https://docs.asp.net/en/latest/data/ef-mvc/intro.html The Contoso University sample web applica ...
- [UWP小白日记-11]在UWP中使用Entity Framework Core(Entity Framework 7)操作SQLite数据库(一)
前言 本文中,您将创建一个通用应用程序(UWP),使用Entity Framework Core(Entity Framework 7)框架在SQLite数据库上执行基本的数据访问. 准备: Enti ...
随机推荐
- CentOS 6.5 中安装 Mysql 5.6,并远程连接Mysql
ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.在安装CentOS时,若选择的是Basic Server(可支持J2EE开发),则新安装好的CentOS系统中默认是已经安装了一个mysq ...
- hadoop之 hadoop 2.2.X 弃用的配置属性名称及其替换名称对照表
Deprecated Properties 弃用属性 The following table lists the configuration property names that are depr ...
- python之集合
集合(set),它是一个无序的,不重复的数据组合,它是作用如下: 1.去重,也就是去除重复的内容.有一点值得注意的是:将一个列表(list)变成集合的时候,会自动去重. 2.关系测试.测试数据之间的交 ...
- VS中Release模式下生成去掉生成pdb文件
1.右键项目,选择属性 2.选择正确的配置,点击高级 3.调试信息选择 none,点击确定.
- 图论 Warshall 和Floyd 矩阵传递闭包
首先我们先说下图论,一般图存储可以使用邻接矩阵,或邻接表,一般使用邻接矩阵在稠密图比较省空间. 我们来说下有向图,一般的有向图也是图,图可以分为稠密图,稀疏图,那么从意思上,稠密图就是点的边比较多,稀 ...
- Android基础知识06—活动的四大启动模式
------ 活动的启动模式 ------ 在实际项目中应该根据特定的需求为每个活动指定恰当的启动模式. 四种启动模式: standard . singleTop . singleTask . sin ...
- python3中判断字串类型
s为字串 s.isalnum() #所有字符都是数字或者字母,为真返回 Ture,否则返回 False. s.isalpha() #所有字符都是字母,为真返回 Ture,否则返回 False. s.i ...
- GET 和 POST 比较整理
差异 上传文件只能使用 POST GET 传输数据有大小限制 GET 传输的数据类型不灵活:GET是使用url来传输数据,那么比如空格字符以及类似&这样的字符就不方便传输.(当然可以使用发送前 ...
- Android———最详细的系统对话框使用
在实际应用开发中,用到系统对话框中的情况几乎是没有的.按开发流程来说,UI工程师都会给出每一个弹窗的样式,故而在实际开发中都是自定义弹窗的. 即使用到的地方不多,但是我们也是需要了解并且能熟练的运用它 ...
- Oracle:sqlplus前缀显示当前用户
第一步:进入SQLPLUS的按照目录,cd $ORACLE_HOME/sqlplus/admin 第二步:查找ll vi glogin.sql 第三步:插入 命令行模式,Go, set sq ...