【发布时间】:2016-03-19 10:46:30
【问题描述】:
我们正在开发小型企业使用的多租户系统,需要为其客户生成发票。基本上,每个租户出于显而易见的原因都希望自己的发票编号序列彼此独立生成。所以第一个租户可以有发票1、2、3,第二个租户可以有相同的,因为他们是独立的业务,彼此一无所知。
我们使用实体框架 7 作为我们的 ORM 和 SQL 2014 作为我们的数据库。我们需要一种方法来生成这些发票编号,而不会在高并发负载下为同一租户意外重复。最初在 EF 中,我们只取发票列的最大值,其中租户 = 当前租户 ID,然后向其添加 1,但经过压力测试后,它为该租户创建了许多重复的发票编号。触发器对此是否更好?序列?我不确定下一步该去哪里。
这是描述我们情况的简化表格布局。请注意最后一张表,发票编号需要如何为每个租户重新启动。这就是我们正在努力实现的目标
+----------+-------------+
| TenantID | TenantName |
+----------+-------------+
| 5 | ABC Company |
| 6 | XYZ Corp |
+----------+-------------+
+----------+------------+----------------+
| TenantID | CustomerID | CustomerName |
+----------+------------+----------------+
| 5 | 2 | Alpa Customer |
| 5 | 5 | Beta Customer |
| 6 | 3 | Delta Customer |
| 6 | 4 | Omega Customer |
+----------+------------+----------------+
+----------+------------+-----------+-------------------------------------------------------+
| TenantID | CustomerID | InvoiceID | InvoiceNumber(this one needs to restart per tenant) |
+----------+------------+-----------+-------------------------------------------------------+
| 5 | 2 | 1 | 1 |
| 5 | 2 | 7 | 2 |
| 5 | 5 | 2 | 3 |
| 5 | 5 | 4 | 4 |
| 5 | 5 | 5 | 5 |
| 6 | 3 | 8 | 1 |
| 6 | 4 | 3 | 2 |
| 6 | 4 | 6 | 3 |
+----------+------------+-----------+-------------------------------------------------------+
基于@ERIKE 的回答 我最终在 TenantID 和 InvoiceNumber 周围添加了一个唯一约束,然后我取发票编号的最大值并添加一个并尝试插入。这是围绕 C# 中的 do while 循环进行的。每当引发唯一约束错误时,它会再次重试
bool retryInsert;
do
{
try
{
retryInsert = false;
var invNo = (db.tbl_Invoice
.Where(t => t.TenantID == invoice.TenantID)
.Max(t => t == null ? 0 : t.InvoiceNumber)
) + 1;
invoice.InvoiceNumber = invNo;
db.tbl_Invoice.Add(invoice);
db.SaveChanges();
}
catch (DbUpdateException ex)
{
retryInsert = false;
var sqlexception = ex.InnerException as SqlException;
if (sqlexception != null)
{
if (sqlexception.Errors.OfType<SqlError>()
.Any(se => se.Number == 2627))
{
retryInsert = true;
}
else throw ex;
}
}
} while (retryInsert);
return invoice;
【问题讨论】:
-
“出于显而易见的原因”。它们对我来说并不明显。也就是说,发票编号是由数据库生成的任意(但保证是唯一的)标识符。通过添加此要求,您实质上是在说最简单的任意形式(标识值或序列)还不够任意,因此您将增加操作/技术复杂性以获得我很难证明的收益。
-
我了解您的来历,但我应该更清楚,而不是仅仅说“出于明显的原因”。这很明显,因为它是产品客户提出的业务需求。对他们来说,更实际的是知道他们的发票编号是根据自己公司的销售额而不是外部实体的销售额而增加的。
标签: c# sql-server entity-framework