Как я могу генерировать случайные числа Unqiue в C#

public int GenPurchaseOrderNum()
{
    Random random = new Random();
    _uniqueNum = random.Next(13287, 21439);
    return UniqueNum;
}

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

Номер отделения связи раньше имел ограничение на уникальность данных, это вынуждает сотрудника генерировать отделение связи во всех случаях, таким образом, дб не бросает ошибку ограничения на уникальность данных.

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

Что мне делать?

Я надеюсь, что мой вопрос достаточно ясен

5
задан µBio 17 June 2010 в 19:49
поделиться

10 ответов

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

  1. Удалите все ограничения NOT NULL, которые у вас есть на поле.
  2. Иметь хранимую процедуру, которую вы используете для создания нового PO, которая оставляет поле PO # NULL. Null наиболее подходит в описанном случае, поскольку в мире DB NULL означает "неизвестно", а поскольку у вас на самом деле нет PO #, оно неизвестно.
  3. Используйте хранимую процедуру, которая обновляет поле после завершения сделки, чтобы увеличить его до следующего доступного номера PO. Это будет происходить на стороне сервера, поэтому не имеет значения, с какого клиента приходит обновление, оно все равно будет уникальным для этой таблицы. Затем эта хранимая процедура может вернуть обновленный набор результатов (если требуется) клиенту, чтобы он мог увидеть новый номер PO #.

Это взгляд с 20-километровой высоты.

11
ответ дан 18 December 2019 в 05:31
поделиться

Из того, что вы написали, кажется, что вы идете неверным путем: Вы путаете случайность с уникальностью.

Вы убрали ограничение, специфичное для домена, чтобы оно соответствовало написанному вами коду. Если значение PONumber не имеет никакого другого значения, кроме уникальности, попросите базу данных сгенерировать его для вас, или сгенерируйте GUID (если база данных не может), что даст вам некоторую гарантию того, что сгенерированное значение будет уникальным.

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

0
ответ дан 18 December 2019 в 05:31
поделиться

Как и на предыдущих плакатах, я бы рекомендовал уникальное значение вместо случайного. Генератор последовательности, который предлагает Ремус, вероятно, лучший подход.

Однако, если вам действительно действительно нужно случайное значение, я бы рекомендовал использовать RNGCryptoServiceProvider вместо класса Random, потому что он более случайный. Посетите MSDN для дополнительной информации . Также есть хороший вопрос StackOverflow по RNGCryptoServiceProvider .

0
ответ дан 18 December 2019 в 05:31
поделиться

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

Предположим, что ваша исходная таблица называется PurchaseOrder и имеет структуру, которая выглядит примерно так:

table PurchaseOrder
(
    PurchaseOrderID int identity not null,
    -- some other fields that are core to a purchase order
    -- ...
    PONumber int not null,
    -- some other fields that are related to a purchase order when the deal is set
    -- ...

    -- define primary key on PuchaseOrderID
    -- define unique constraint on PONumber field
)

Я предлагаю разбить эту таблицу на части, чтобы она выглядела примерно так:

table PurchaseOrder
(
    PurchaseOrderID int identity not null,
    -- some other fields that are core to a purchase order
    -- ...

    -- define primary key on PuchaseOrderID
)


table PurchaseOrderDealInfo
(
    PurchaseOrderID int not null,
    PONumber int identity not null,
    -- some other fields that are related to a purchase order when the deal is set
    -- ...

    -- define primary key on PurchaseOrderID
    -- define foreign key on PurchaseOrderID related to PurcahseOrder.PurchaseOrderID
    -- define unique constraint on PONumber field
)

Теперь ваша сделка информация в отдельной таблице. Любые заказы на покупку, для которых еще не установлена ​​сделка, просто не будут иметь соответствующей записи в таблице PurchaseOrderDealInfo. Да, вам нужно будет объединить таблицы вместе, если вы хотите получить всю информацию, относящуюся к конкретному заказу на покупку. Однако вы получаете некоторые преимущества:

  1. Вы все еще можете применить уникальное ограничение к столбцу PONumber.

  2. Вы можете воспользоваться функцией идентификации SQL Server, чтобы сгенерировать для вас свой PONumber

  3. Если бы в вашей таблице были какие-либо другие столбцы, специфичные для сделки, которые вы сделали обнуляемыми, просто потому, что они не имели бы значения до тех пор, пока не будет заключена сделка. set, то, как только вы переместите эти столбцы в таблицу PurchaseOrderDealInfo, вы можете запретить использование нулей (при необходимости).

  4. Если вы хотите получить только заказы на покупку, в которых есть сделки, вы можете просто запросить таблицу PurcahseOrderDealInfo, не задавая никаких критериев фильтрации. Конечно, если вам также нужна информация из таблицы PurchaseOrder, вам нужно будет выполнить внутреннее соединение.

0
ответ дан 18 December 2019 в 05:31
поделиться
  • не используйте 0 для неизвестных значений. Добавьте обратно уникальное ограничение и используйте NULL для представления неизвестных/не сгенерированных значений. Если хотите, отображайте NULL как 0 для пользователя, но это ортогонально к данному вопросу.
  • Не используйте random для генерации уникального номера, а затем пытайтесь вставить, вы излишне усложните логику повторными попытками и регенерациями. Используйте генератор последовательностей, как UPDATE seqnces SET sequence = sequence+1 OUTPUT INSERTED.sequence WHERE key = 'somekey'
  • Не используйте random для генерации значений, важных для бизнеса, таких как номера заказов на поставку. Используйте генератор последовательности, как показано выше.

Обновлено

В SQL Server 2008 и выше вы можете иметь уникальный фильтрованный индекс, который будет действовать как ограничение для всего, что не равно 0:

create unique index idxTbaleUniquePoNumber 
 on <table> (po_number) 
 where (po_number > 0);

Вроде как съесть торт и получить его тоже...

5
ответ дан 18 December 2019 в 05:31
поделиться

Если вам действительно нужна серия уникальных случайных чисел в диапазоне (скажем, от 13287 до 21439), я бы создал список всех допустимых целых чисел, а затем случайным образом поменял их местами. Что-то вроде несортировки, если хотите. Это даст вам список случайных, уникальных чисел.

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

2
ответ дан 18 December 2019 в 05:31
поделиться

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

Я думаю, вам следует сделать шаг назад и четко сформулировать свои цели без учета текущей физической реализации.

Как правило, системы заказов требуют уникальных PO, поэтому вам нужно иметь уникальное ограничение на это. Как правило, системы не хранят PO и "предварительные PO" одинаково. Предварительные заказы" обычно называются котировками или чем-то подобным, и они часто имеют свою собственную систему нумерации. Таким образом, обычно нет конфликта в наличии номеров NULL или 0 PO, потому что нет ничего, что не является реальным PO, хранящимся вместе с реальными PO. Даже в системах, которые хотят хранить их вместе, они просто идут вперед и присваивают им номер в той же последовательности.

Кроме того, идентификатор вполне подходит для генерации номеров PO.

0
ответ дан 18 December 2019 в 05:31
поделиться

Если вам действительно нужно случайное значение, вместо того, чтобы возвращать int , вы можете использовать GUID. Они гарантированно будут уникальными:

GUID - это 128-битное целое число (16 байтов), которое может использоваться на всех компьютерах и сетях, где требуется уникальный идентификатор. Такой идентификатор имеет очень низкую вероятность дублирования.

Источник

В качестве альтернативы можно вести учет последнего использованного числа и просто увеличивать его каждый раз, когда вам нужен новый заказ на покупку. Убедитесь, что вы установили блокировку, чтобы два процесса не пытались увеличить его одновременно.

5
ответ дан 18 December 2019 в 05:31
поделиться

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

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

0
ответ дан 18 December 2019 в 05:31
поделиться

Ваш автономер PK в базе данных можно использовать как уникальный номер PO... просто прочитайте и скопируйте его, когда он станет "настоящим" ненулевым номером PO.

Это не будет "случайным", но будет уникальным.

Теперь ответ для ботаников: Компьютер не может генерировать случайные числа без хаотических "случайных" семян

.
0
ответ дан 18 December 2019 в 05:31
поделиться