不同前缀的自动递增 - EF

Auto increment for different prefixes - EF

所以我 table 有发票。目前 Key 列用作发票编号。当然,它会自动递增,因为它是一个键列。

现在该应用程序将被不同国家的不同公司使用。因此,如果他们都创建发票,则发票编号不正确。

因此,在国家 A 中,最新的发票编号可能是 2018002345,而在国家 B 中,某人应该能够创建 ID 为 201800001 以及之后为 201800002 的发票。

当然,默认的 [Key] 列对此不起作用,我想?

除此之外,为它们添加前缀是个好主意,因此前缀带有国家代码:NL20180002345 和 US2018000001。 (当前缀唯一时,也许可以使用 Key 列?)。 在完美的情况下,数字递增 +1,但如果这真的很困难,那么有 99% 概率的解决方案是接受 table。

所以我正在寻找一种正确的方法来处理这种情况。它是一个现有的生产应用程序,因此无法突然更改 Key 列,如果更改它们将需要迁移。

我想避免我首先必须调用数据库来检索最后一个键然后插入一个递增的键的情况,这会产生问题并且无法缩放。

数据库是使用代码优先迁移生成的。我更喜欢可以使用代码优先注释制作的解决方案。但是,还有第二个项目使用没有 Entity Framework 的数据库,它使用的是 Dapper。那么另一方面,MSSQL 解决方案也可以吗?

当前实体:

发票

public class Invoice
{
    public int InvoiceId { get; set; }
    public int ContactId { get; set; }
    public int BillingAddressId { get; set; }
    public int? OrderId { get; set; }
    public int? RefundInvoiceId { get; set; }
    public DateTime Date { get; set; }
    //more properties
    [Timestamp]
    public byte[] Timestamp { get; set; }
    public DateTime? PayDate { get; set; }
    public PaymentStatusEnum PaymentStatus { get; set; }
    [ForeignKey("BillingAddressId")]
    public Address BillingAddress { get; set; }
}

因此它链接到一个地址,该地址链接到拥有国家代码的国家。

地址

public class Address
{
    public int addressId { get; set; }
    public int countryId { get; set; }
    //more properties
    public bool validated { get; set; }
    public AddressTypeEnum addressType { get; set; }
    public Country Country { get; set; }
}

国家/地区

public class Country
{
    public int CountryId { get; set; }
    public string CountryCode { get; set; }
    public string CountryName { get; set; }
    public double Taxpercentage { get; set; }
    public int CurrencyId { get; set; }
    [ForeignKey("CurrencyId")]
    public Currency Currency { get; set; }
}

作为 server-side 解决方案,您可以使用 insert trigger on your invoice table and equip the field value in your trigger code. You could use (sequence objects) 来生成数字,这两个国家的两个不同序列可能对您有用。您的发票 ID 字段可以是 nvarchar 字符串,因此您的触发代码也可以应用国家/地区前缀。

然后,在客户端,使用 DatabaseGenerated 属性标记该字段,如下所示:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string InvoiceId { get; set; }

这会指示 EF 在您插入或更新 table 时在同一往返行程中获取列值(在您的触发器中创建)。

一个简单的例子:

create table Invoice (
  Id int not null primary key identity(1,1),
  InvoiceId nvarchar(20),
  CountryId int not null
  -- etc.
)

CREATE SEQUENCE InvNo_US 
    START WITH 1000000  
    INCREMENT BY 1;  
GO  

CREATE TRIGGER TriInvoice_AI
ON Invoice AFTER INSERT
AS 
BEGIN
  SET NOCOUNT ON;

  declare @id int, @country_id int, @seq bigint;

  DECLARE c CURSOR LOCAL FAST_FORWARD FOR   
    SELECT i.Id, i.CountryId from inserted i
    ORDER BY i.Id;

  open c;
  fetch next from c into @id, @country_id;

  while @@FETCH_STATUS = 0
  begin
    /* TODO: At this point you may use different sequence object depending on @country_id,
       you may apply different country prefixed and maybe do other specific formatting to the InvoiceId 
       This example always just uses 'US' and doesn't take the @country_id in account at all. */
    set @seq = NEXT VALUE FOR InvNo_US;
    update Invoice set InvoiceId = 'US' + cast(@seq as nvarchar) where Id=@id;
    fetch next from c into @id, @country_id;
  end
  close c;
  deallocate c;
END

这样测试:

insert into Invoice (CountryId) values (42);
select * from Invoice;