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 - bigintGetDate() ?-- Time - datetime)Go 10Select * From #T查詢結果:
| 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 1Increment By 10MinValue -9223372036854775808MaxValue 9223372036854775807Cache 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 1000INCREMENT BY 5MINVALUE -2147483648MAXVALUE 2147483647CACHE 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/
原文:http://www.cnblogs.com/tdfblog/p/entity-framework-core-hilo.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的Entity Framework Core 使用HiLo生成主键的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Microsoft.AspNetCo
- 下一篇: 开源纯C#工控网关+组态软件(六)图元组