Итак, у меня есть таблица со счетами-фактурами. В настоящее время столбец Ключ используется как номер счета. Он автоматически увеличивается, потому что, конечно же, это ключевой столбец.

Теперь приложение будут использовать разные компании в разных странах. Таким образом, нумерация счета-фактуры неверна, если они оба создают счет-фактуру.

Таким образом, в то время как в стране A последний номер счета может быть 2018002345, в стране B кто-то должен иметь возможность создать счет с идентификатором 201800001, а затем 201800002.

Конечно, я думаю, столбец по умолчанию [Key] для этого не подойдет?

Вдобавок к этому рекомендуется иметь для них префикс, например, префикс с кодом страны: NL20180002345 и US2018000001. (Может быть, можно использовать столбец Key, когда префиксы уникальны?). В идеальной ситуации числа увеличиваются на +1, но если это ДЕЙСТВИТЕЛЬНО сложно, тогда приемлемо решение с вероятностью 99%.

Поэтому я ищу правильный способ справиться с этой ситуацией. Это существующее и производственное приложение, поэтому внезапно изменить столбец «Ключ» невозможно, при их изменении потребуются миграции.

Я бы хотел избежать ситуации, когда мне сначала нужно вызвать базу данных, чтобы получить последний ключ, а затем вставить один увеличенный, что создает проблемы и не масштабируется.

База данных создается с использованием миграций Code-First. Я бы предпочел решение, которое можно было бы сделать с помощью аннотаций, начинающихся с кода. Однако есть второй проект, использующий базу данных без 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; }
}
0
CularBytes 27 Фев 2018 в 12:10

1 ответ

Лучший ответ

В качестве серверного решения вы можете использовать вставьте триггер в таблицу счетов и укажите значение поля в коде триггера. Вы можете использовать ( объекты последовательности ) для генерации чисел, возможно, вам могут подойти две различные последовательности для двух стран. Поле идентификатора счета-фактуры может быть строкой nvarchar, поэтому в вашем коде триггера также может применяться префикс страны.

Затем на стороне клиента пометьте это поле атрибутом DatabaseGenerated следующим образом:

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

Это указывает EF на получение значения столбца (которое было создано в вашем триггере) в том же цикле приема-передачи, когда вы вставляете или обновляете эту таблицу.

Упрощенный пример:

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;
2
KarloX 27 Фев 2018 в 14:59