第一个答案,问题里的例子写完后就变了。
您说零件 ID 中存在间隙是否可以,因为“某些零件可能会在此过程中被删除”。
那么,你的例子有什么区别:
Car PartID
54654 1
54654 2
54654 3
78787 1
78787 2
99666 1
99666 2
99666 5
99666 7
还有这个变体:
Car PartID
54654 1
54654 2
54654 3
78787 4
78787 5
99666 6
99666 7
99666 8
99666 9
在第二个变体中,每个部件都有一些对于每辆车来说都是唯一的 ID(它也是全球唯一的,但这并不重要)。在第二个变体中PartID
指定将部件插入表中的顺序,与第一个变体中相同。
所以,我会用一个简单的IDENTITY
column:
Parts
PartID int IDENTITY NOT NULL (PRIMARY KEY)
CarLicenseNum int NOT NULL (FOREIGN KEY)
PartName varchar(255)
供应商订单示例更新
更新的问题中最重要的一点是“监管原因”。它回答了为什么你想做这种不自然的事情的问题。 “监管”和效率往往是对立的。
本质上,这意味着你必须使用可序列化事务隔离级别 https://msdn.microsoft.com/en-AU/library/ms173763.aspx插入新行并计算序列中的下一个数字时。它会损害并发/吞吐量,但会保证多用户环境中的一致性和“安全”。
我不知道如何在实体框架中做到这一点,它应该是可能的。但是,同样,出于“监管原因”,我会将这个逻辑放入数据库的存储过程中,并确保普通用户没有对数据库的写访问权限。Orders
直接表,但仅有权执行此专用存储过程。您可以在 EF 代码中复制此存储过程的逻辑,但数据库本身将开放通过其他应用程序完成的更改,这可能不符合法规要求。
您可以使用单独的表来实现它,该表存储每个供应商的最新序列号,或者您可以即时读取最后一个最大序列号。如果每个供应商只有很少的订单,那么这个包含最新计数器值的单独表将相当于Orders
表,你不会得到太多。无论如何,拥有一个合适的索引是关键。获取最新的计数器值将是索引中的一项搜索。
这是不使用额外表的存储过程的示例。
确保Orders
表有唯一索引(SupplierId, OrderCountForSupplier)
。事实上,即使您使用额外的表来强制执行约束,也必须拥有此索引。
CREATE PROCEDURE [dbo].[AddOrder]
@ParamSupplierID int,
@ParamProductSerial varchar(10),
@ParamQuantity int,
@NewOrderID int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
BEGIN TRY
DECLARE @VarMaxCounter int;
SELECT TOP(1) @VarMaxCounter = OrderCountForSupplier
FROM dbo.Orders
WHERE SupplierID = @ParamSupplierID
ORDER BY OrderCountForSupplier DESC;
SET @VarMaxCounter = ISNULL(@VarMaxCounter, 0) + 1;
INSERT INTO dbo.Orders
(SupplierID
,OrderCountForSupplier
,ProductSerial
,Quantity)
VALUES
(@ParamSupplierID
,@VarMaxCounter
,@ParamProductSerial
,@ParamQuantity);
SET @NewOrderID = SCOPE_IDENTITY();
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- TODO: handle the error
SET @NewOrderID = 0;
ROLLBACK TRANSACTION;
END CATCH;
END
GO