正确生成唯一的发票id
本文关键字:id 唯一 | 更新日期: 2023-09-27 18:16:14
我被要求清理其他人的控制器代码,该代码会生成发票,但我遇到了一些我不知道如何修复的问题。有问题的代码如下(这是使用EF 6:代码优先(:
var invid = db.TransportJobInvoice.Where(c => c.CompanyId == CompanyId)
.Max(i => i.InvoiceId);
var invoiceId = invid == null ? 1 : (int)invid + 1;
该代码应该根据创建发票的公司生成invoiceId
。因此,这方面的一个小表格可能如下所示:
------------------------------
| Id | CompanyId | InvoiceId |
------------------------------
| 1 | 1 | 1 |
------------------------------
| 2 | 1 | 2 |
------------------------------
| 3 | 1 | 3 |
------------------------------
| 4 | 2 | 1 |
------------------------------
| 5 | 2 | 2 |
------------------------------
正如您所看到的,invoiceId
将根据相关公司的当前发票数量生成。然而,我认为建议两个线程可以在评估此行之前执行查询是合理的:
var invoiceId = invid == null ? 1 : (int)invid + 1;
这将导致针对两个不同的发票生成相同的CCD_ 3。
有没有一个简单的解决方案,可能利用实体框架自动做到这一点?
我建议使用主键的标识,非常重要!
然后,我会为"CustomerInvoiceID"添加一列,并在"CustomerID和CustomerInvoiceID"上放置一个复合唯一密钥
然后,创建一个存储过程,在插入字段CustomerInvoiceID后填充该字段,下面是一些伪代码:
CREATE PROCEDURE usp_PopulateCustomerInvoiceID
@PrimaryKey INT, --this is your primary key identity column
@CustomerID INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @cnt INT;
SELECT @CNT = COUNT(1)
FROM TBL
WHERE CustomerID = @CustomerID
AND PrimaryKeyColumn <= @PrimaryKey
UPDATE tbl
SET CustomerInvoiceID = @cnt + 1
WHERE PrimaryKeyColumn = @PrimaryKey
END
两种可能性:
服务器端:不要计算客户端上的最大值(ID(+1。相反,作为INSERT语句的一部分,通过INSERT计算max(ID(+1。。SELECT语句。
客户端:在客户端上生成一个GUID,并将其用作InvoiceID,而不是递增的int。
一种完全不同的方法是为每个CustomerId
创建一个单独的NextId
表。当添加新客户时,您需要在此表中添加一个新行。它的优点是,即使允许删除发票,分配给发票的编号也可以保持唯一。
create procedure GetInvoiceIdForCustomer
@CustomerId as Int,
@InvoiceId as Int Output
as
begin
set nocount on
begin transaction
update CustomerInvoiceNumbers
set @InvoiceId = NextId, NextId += 1
where CustomerId = @CustomerId
if @@RowCount = 0
begin
set @InvoiceId = 1
insert into CustomerInvoiceNumbers ( CustomerId, NextId ) values ( @CustomerId, @InvoiceId + 1 )
end
commit transaction
end
end
如果在SQL Server中使用Identity
字段,则会自动处理。
我不知道你是否可以自动生成发票id,除非它被威胁为外键(我认为不是(。
使用lock语句可以解决多个线程的问题。
lock (myLock)
{
var invid = db.TransportJobInvoice.Where(c => c.CompanyId == CompanyId)
.Max(i => i.InvoiceId);
var invoiceId = invid == null ? 1 : (int)invid + 1;
}
这将保证只有线程在执行这些语句。
但是要小心,当这些语句多次并行执行时,这可能会导致性能问题,并且执行查询需要相当长的时间。