Entity Framework Core 使用HiLo生成主键
HiLo是在NHibernate中生成主鍵的一種方式,不過現(xiàn)在我們可以在Entity Framework Core中使用。所以在這篇內(nèi)容中,我將向您在介紹如何在Entity Framework Core中使用HiLo生成主鍵。
什么是Hilo?
HiLo是High Low的簡寫,翻譯成中文叫高低位模式。
HiLo是由“Hi”和“Lo”兩部分生成主鍵的一種模式。“Hi”部分來自數(shù)據(jù)庫,“Lo”部分在內(nèi)存中生成以創(chuàng)建唯一值。請記住,“Lo”是一個(gè)范圍數(shù)字,如0-100。因此,當(dāng)“Hi”部分用完“Lo”范圍時(shí),再次進(jìn)行數(shù)據(jù)庫調(diào)用以獲得下一個(gè)“Hi數(shù)字”。所以HiLo模式的優(yōu)點(diǎn)在于您預(yù)先可以知道主鍵的值,而不用每次都與數(shù)庫據(jù)發(fā)生交互。
總結(jié)有以下四點(diǎn):
“Hi”部分由數(shù)據(jù)庫分配,兩個(gè)并發(fā)請求保證得到唯一的連續(xù)值;
一旦獲取“Hi”部分,我們還需要知道“incrementSize”的值(“Lo”條目的數(shù)量);
“Lo”取的范圍:[0,incrementSize];
標(biāo)識范圍的公式是:(Hi - 1) * incrementSize) + 1?到?(Hi - 1) * incrementSize) + incrementSize)
當(dāng)所有“Lo”值使用完時(shí),需要重新從數(shù)據(jù)庫中取出一個(gè)新的“Hi”值,并將“Lo”部分重置為0。
在這里演示在兩個(gè)并發(fā)事務(wù)中的例子,每個(gè)事務(wù)插入多個(gè)實(shí)體:
Sql Server 序列
在EF Core中使用HiLo生成主鍵,我們還需要了解Sql Server中一個(gè)概念序列(Sequence)。
序列是在SQL Server 2012中引入的(不過Oracle很早就已經(jīng)實(shí)現(xiàn)了http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_6015.htm)。序列是用戶定義的對象,它根據(jù)創(chuàng)建的屬性生成一系列數(shù)值。它與?Identity?列相似,但它們之間有很多不同之處。例如,
-
序列用于生成數(shù)據(jù)庫范圍的序列號;
-
序列不與一個(gè)表相關(guān)聯(lián),您可以將其與多個(gè)表相關(guān)聯(lián);
-
它可以用于插入語句來插入標(biāo)識值,也可以在T-SQL腳本中使用。
創(chuàng)建序列示例的SQL語句:
Create Sequence [dbo].[Sequence_Test] As [BigInt] ? ? ? ? --整數(shù)類型Start With 1 ? ? ? ?--起始值Increment By 1 ? ? ?--增量值MinValue 1 ? ? ? ? ?--最小值MaxValue 9999999 ? ?--最大值Cycle ? ? ? ? ? ? ? --達(dá)到最值循環(huán) [ CYCLE | NO CYCLE ]Cache ?5; ? ? ? ? ? --每次取出5個(gè)值緩存使用 [ 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查詢結(jié)果:
| 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 |
關(guān)于序列更多的內(nèi)容,可以查閱如下資料:
-
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中生成主鍵。
為了演示,我們創(chuàng)建了兩個(gè)沒有關(guān)系的實(shí)體。
? ?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按慣例配置一個(gè)名為Id或<type name>Id作為實(shí)體的主鍵屬性。現(xiàn)在我們需要?jiǎng)?chuàng)建我們的DBContext,在這里我們創(chuàng)建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構(gòu)造函數(shù)初始化數(shù)據(jù)庫,類型于EF 6中的DropCreateDatabaseAlways;
-
OnConfiguring()?方法用于配置數(shù)據(jù)庫鏈接字符串;
-
OnModelCreating方法用于定義實(shí)體模型。要定義HiLo序列,請使用ForSqlServerUseSequenceHiLo擴(kuò)展方法。您需要提供序列的名稱。
運(yùn)行應(yīng)用程序,您應(yīng)該在創(chuàng)建“EFSampleDB”數(shù)據(jù)庫中看到Product表、Category表和DBSequenceHiLo序列。
以下是創(chuàng)建DBSequenceHiLo的腳本。
Create Sequence [dbo].[DBSequenceHiLo] As [BigInt] Start With 1Increment By 10MinValue -9223372036854775808MaxValue 9223372036854775807Cache Go正如你所看到的,它從1開始,遞增是10。
現(xiàn)在向數(shù)據(jù)庫中添加一些數(shù)據(jù)。以下代碼首先添加3個(gè)Category實(shí)體和調(diào)用SaveChanges(),然后添加3個(gè)Product實(shí)體并調(diào)用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();} 當(dāng)這個(gè)代碼第一次被執(zhí)行,Clothing?實(shí)體通過Add方法增加到DBContext時(shí),就會向數(shù)據(jù)庫調(diào)用獲取序列的值,我們也可以通過SQL Server Profiler來驗(yàn)證它。
次調(diào)用dataContext.SaveChanges()時(shí),3個(gè)Category實(shí)體將被保存。查看執(zhí)行的SQL語句。主鍵值已經(jīng)被生成,序列值的獲取也只執(zhí)行了一次。
即使插入3個(gè)Product實(shí)體,序列值也不會從數(shù)據(jù)庫中獲取。只有當(dāng)插入10條記錄(Lo部分耗盡)時(shí),才會向數(shù)據(jù)庫調(diào)用獲得下一個(gè)(Hi部分)序列值。
向HiLo運(yùn)用到單個(gè)實(shí)體
上面的代碼兩個(gè)表共用一個(gè)HiLo序列。如果您只想針對一個(gè)特定的表,那么您可以使用下面的代碼。
? ?modelbuilder.Entity<Category>().Property(o => o.CategoryID).ForSqlServerUseSequenceHiLo();這段代碼將創(chuàng)建一個(gè)默認(rèn)名稱為“EntityFrameworkHiLoSequence”的新序列,因?yàn)闆]有指定名字。您也可以定義多個(gè)HiLo序列。例如:
? ?protected override void OnModelCreating(ModelBuilder modelbuilder) ? ?{modelbuilder.ForSqlServerUseSequenceHiLo("DBSequenceHiLo");modelbuilder.Entity<Category>().Property(o => o.CategoryID).ForSqlServerUseSequenceHiLo();}在數(shù)據(jù)庫中,將創(chuàng)建兩個(gè)序列。Category實(shí)體將使用EntityFrameworkHiLoSequence序號,所有其它實(shí)體使用DBSequenceHiLo序列。
配置HiLo序列
ForSqlServerHasSequence擴(kuò)展方法不能更改起始值和增量值的選項(xiàng)。但是,有一種方法來定義這些選項(xiàng)。首先,使用HasSequence方法定義序列的StartAt和IncrementBy選項(xiàng),然后再使用ForSqlServerUseSequenceHiLo()擴(kuò)展方法,要保持序列的名稱一致。例如:
? ?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所以當(dāng)我們執(zhí)行相同的代碼插入3個(gè)Category實(shí)體,那么主鍵的值將從1000開始。
而且由于IncrementBy選項(xiàng)設(shè)置為“5”,所以當(dāng)在上下文中添加第6個(gè)插入時(shí),將進(jìn)行數(shù)據(jù)庫調(diào)用以獲得下一個(gè)序列值。以下是插入3個(gè)Category實(shí)體然后插入3個(gè)的Product實(shí)體時(shí)SQL Server profiler的屏幕截圖,您可以看到數(shù)據(jù)庫調(diào)用獲取序列的下一個(gè)值的次數(shù)是2次。
如果您對在Entity Framework Core中使用HiLo生成主鍵感興趣,不防自己動(dòng)手測試一下。
參考資料:
-
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社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的Entity Framework Core 使用HiLo生成主键的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Microsoft.AspNetCo
- 下一篇: 自定义路由匹配和生成