Entity Framework Core 使用HiLo生成主键

摘要:
HiLo是由“Hi”和“Lo”两部分生成主键的一种模式。因此,当“Hi”部分用完“Lo”范围时,再次进行数据库调用以获得下一个“Hi数字”。在这里演示在两个并发事务中的例子,每个事务插入多个实体:SqlServer序列在EFCore中使用HiLo生成主键,我们还需要了解SqlServer中一个概念序列。publicclassCategory{publicintCategoryID{get;set;}publicstringCategoryName{get;set;}}publicclassProduct{publicintProductID{get;set;}publicstringProductName{get;set;}}请记住,EFCore按惯例配置一个名为Id或Id作为实体的主键属性。要定义HiLo序列,请使用ForSqlServerUseSequenceHiLo扩展方法。运行应用程序,您应该在创建“EFSampleDB”数据库中看到Product表、Category表和DBSequenceHiLo序列。

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模式的优点在于您预先可以知道主键的值,而不用每次都与数库据发生交互

总结有以下四点:

  1. “Hi”部分由数据库分配,两个并发请求保证得到唯一的连续值;
  2. 一旦获取“Hi”部分,我们还需要知道“incrementSize”的值(“Lo”条目的数量);
    “Lo”取的范围:[0,incrementSize];
  3. 标识范围的公式是:(Hi - 1) * incrementSize) + 1(Hi - 1) * incrementSize) + incrementSize)
  4. 当所有“Lo”值使用完时,需要重新从数据库中取出一个新的“Hi”值,并将“Lo”部分重置为0。

在这里演示在两个并发事务中的例子,每个事务插入多个实体:

Entity Framework Core 使用HiLo生成主键第1张

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

查询结果:

IdTime
12017-11-23 16:46:50.613
22017-11-23 16:46:50.643
32017-11-23 16:46:50.667
42017-11-23 16:46:50.677
52017-11-23 16:46:50.687
62017-11-23 16:46:50.697
72017-11-23 16:46:50.707
82017-11-23 16:46:50.717
92017-11-23 16:46:50.730
102017-11-23 16:46:50.740

关于序列更多的内容,可以查阅如下资料:

使用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序列。

Entity Framework Core 使用HiLo生成主键第2张

以下是创建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来验证它。
Entity Framework Core 使用HiLo生成主键第3张

次调用dataContext.SaveChanges()时,3个Category实体将被保存。查看执行的SQL语句。主键值已经被生成,序列值的获取也只执行了一次。
Entity Framework Core 使用HiLo生成主键第4张

即使插入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序列。

Entity Framework Core 使用HiLo生成主键第5张

配置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实体,那么主键的值将从1000开始。

Entity Framework Core 使用HiLo生成主键第6张

而且由于IncrementBy选项设置为“5”,所以当在上下文中添加第6个插入时,将进行数据库调用以获得下一个序列值。以下是插入3个Category实体然后插入3个的Product实体时SQL Server profiler的屏幕截图,您可以看到数据库调用获取序列的下一个值的次数是2次。
Entity Framework Core 使用HiLo生成主键第7张

如果您对在Entity Framework Core中使用HiLo生成主键感兴趣,不防自己动手测试一下。

参考资料:

免责声明:文章转载自《Entity Framework Core 使用HiLo生成主键》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇LOJ-2362 蚯蚓 队列优化loadrunner---&amp;lt;二&amp;gt;---菜鸟对cookie的思考下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

黑客入侵的常法

      1.无论什么站,无论什么语言,我要渗透,第一件事就是扫目录,最好一下扫出个上传点,直接上传 shell ,诸位不要笑,有时候你花很久搞一个站,最后发现有个现成的上传点,而且很容易猜到,不过这种情况发生在 asp 居多!    2.asp ( aspx )+MSSQL 先考虑注入,一般的注入都有 DBowner 权限可以直接写 shell ;如果...

MySQL SQL优化

前言 有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧。 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础。 优化目标 1.减少 IO 次数 IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO...

C#连接一些常见的数据库(sql,Access,Oracle,Sybase,DB2)

1.C#连接连接Access //导入命名空间 using System.Data; using System.Data.OleDb; .. string strConnection="Provider=Microsoft.Jet.OleDb.4.0;"; strConnection+=@"Data Source=D:""Northwind.mdb";...

sharding-jdbc

https://www.cnblogs.com/fengpinglangjingruma/p/14005759.html sharding-jdbc 提供了4种分片算法: 1、精确分片算法 精确分片算法(PreciseShardingAlgorithm)用于单个字段作为分片键,SQL中有 = 与 IN 等条件的分片,需要在标准分片策略(StandardSh...

Oracle安装

参考:https://blog.csdn.net/wudiyong22/article/details/78904361 一、Oracle下载 注意Oracle分成两个文件,下载完后,将两个文件解压到同一目录下即可。 路径名称中,最好不要出现中文,也不要出现空格等不规则字符。百度云盘:https://pan.baidu.com/s/14cBI8mAro7r...

生物数据库与在线工具

生物数据库       生物数据库是收集自科学实验、出版文献、高通量实验技术和计算分析等生命科学信息库,它包含来自基因组学、蛋白质组学、代谢组学、微阵列基因表达和系统发育学等领域的信息。       生物数据库大致可分为序列、结构和功能数据库。序列数据库储存核酸和蛋白质序列;结构数据库储存RNA和蛋白质的结构信息;功能数据库提供关于基因产物的生理作用信息(...