Rey*_*ldi 6 c# sql-server entity-framework azure-sql-database
我有一个客户和销售表
CUSTOMER
--------------
Id (int auto increment)
Name
SALES
---------------
Id (int auto increment)
CustomerId (int)
OrderTotal (decimal)
Run Code Online (Sandbox Code Playgroud)
有了Guid,我可以做到这一点.
dbTransaction = dbContext.Database.BeginTransaction(isolationLevel);
var customer = new Customer()
{
Id = Guid.NewGuid(),
Name = "John Doe"
};
var sales = new Sales()
{
Id = Guid.NewGuid(),
CustomerId = customer.Id,
OrderTotal = 500
};
dbContext.SaveChanges();
dbTransaction.Commit();
Run Code Online (Sandbox Code Playgroud)
如果我的主键是int(使用DatabaseGeneratedOption.Identity),我该怎么做?
sta*_*ica 15
你不能.进入IDENTITY列的ID 由数据库在插入时生成,并且所有用于规避该ID并自行确定ID的"技巧"可能存在缺陷.
简短回答:如果您在保存之前想要生成ID,请使用GUID(UNIQUEIDENTIFIER)或a SEQUENCE(如果您正在使用SQL Server 2012或更高版本).
甚至不要考虑运行诸如context.Customers.Max(c => c.Id) + 1可行解决方案之类的查询,因为总有可能存在并发数据库访问:在您阅读下一个"免费"之后,另一个进程或线程可能会将新实体持久保存到同一个表中ID,但在存储实体之前.计算下一个空闲ID将容易发生冲突,除非您获取ID,对其执行某些操作以及存储具有该ID的实体的整个操作都是原子的.这可能需要DB中的表锁,这可能是低效的.
(即使使用(我错了 ;请参阅答案结束.)SEQUENCESQL,SQL Server 2012中引入的新功能,也存在同样的问题.)
如果需要在保存对象之前确定对象的ID,请不要使用IDENTITY列中的ID .保持GUID,因为你极不可能与这些碰撞.
没有必要在一个或另一个之间做出选择:你实际上可以吃蛋糕并吃掉它!没有什么可以阻止你有两个ID列,一个是你在外部确定的(GUID),另一个是DB内部的(IDENTITY列); 请参阅Mark Seemann 撰写的博客文章"CQS与服务器生成的ID",以更详细地了解这一想法.以下是一般的想法:
CREATE TABLE Foos
(
FooId INT IDENTITY NOT NULL PRIMARY KEY CLUSTERED,
-- ^^^^^ assigned by the DBMS upon insertion. Mostly for DB-internal use.
Id UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL UNIQUE DEFAULT (NEWID()),
-- ^^ can be dictated and seen by the users of your DB. Mostly for DB-external use.
…
);
CREATE TABLE FooBars
(
FooId INT NOT NULL FOREIGN KEY REFERENCES Foos (FooId),
-- use DB-internal ID in foreign key constraints ^^^^^
…
);
CREATE VIEW PublicFoos AS
SELECT Id, … FROM Foos;
-- ^^ publish the public ID for users of your DB
Run Code Online (Sandbox Code Playgroud)
(确保遵循一些约定,以便始终命名内部和公共ID字段名称.)
SEQUENCEs,SQL Server 2012中引入的功能,是拥有IDENTITY列的可能替代方案.它们会自动增加,并且在使用时获得下一个免费ID时,您可以获得唯一的号码NEXT VALUE FOR SomeSequence.MSDN上提到的一个用例是:
在以下场景中使用序列而不是标识列:[...]应用程序在插入表之前需要一个数字.
一些警告:
获取下一个序列值将需要额外的数据库往返.
与标识列一样,序列可以重置/重新播种,因此存在ID冲突的理论可能性.如果可以提供帮助,最好不要重新定位标识列和序列.
如果您使用获取下一个空闲序列值NEXT VALUE FOR,但随后决定不使用它,则会导致ID中出现"间隙".使用常规(非顺序)GUID显然不会发生差距,因为它们没有固有的排序.