简体   繁体   English

如何在C#中生成随机Unqiue数字

[英]How Can I Generate Random Unqiue Numbers in C#

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

I removed unique constraint from the PONumber column in the db because an employee should only generate PO # when the deal is set. 我从数据库中的PONumber列中删除了唯一约束,因为员工只应在设置交易时生成PO#。 Otherwise, PO # would have 0. 否则,PO#将为0。

PO Number used to have unique constraint, this forces employee to generate PO in all cases so the db doesn't throw unique constraint error. PO号用于具有唯一约束,这会强制员工在所有情况下生成PO,因此db不会抛出唯一约束错误。

Since i removed the unique constraint, any quote doesn't have PO will carry 0 value. 由于我删除了唯一约束,任何报价都没有PO将带有0值。 Otherwise, a unique value is generated for PO #. 否则,为PO#生成唯一值。 However, i don't have a unique constraint in db which makes it hard for me to know whether the application generated PO # is unique or not. 但是,我没有db中的唯一约束,这使我很难知道应用程序生成的PO#是否唯一。

What should i do? 我该怎么办?

I hope my question is clear enough 我希望我的问题很清楚

A GUID is a bit high in the way of overhead. GUID在开销方面有点高。 Specifically, it sounds like you need a human readable number for the PO#, which makes a GUID impractical. 具体来说,听起来你需要一个人类可读的PO#号码,这使得GUID不切实际。 I'd be more inclined to use the following scenario. 我更倾向于使用以下场景。

  1. Remove any NOT NULL constraints you have on the field. 删除字段上的任何NOT NULL约束。
  2. Have a stored procedure that you use to create a new PO that leaves the PO # field NULL. 有一个存储过程,用于创建新的PO,使PO#字段为NULL。 Null is most appropriate in the case described since in the world of DB NULL means "unknown" and since you don't actually HAVE a PO #, it IS unknown. Null在所描述的情况下是最合适的,因为在DB NULL的世界中意味着“未知”并且因为你实际上没有PO#,所以它是未知的。
  3. Use a stored procedure that updates the field when the deal is complete to increment to the next available PO number. 使用在交易完成时更新字段的存储过程,以递增到下一个可用的PO编号。 This will happen server side, so it doesn't matter what client the update comes from it will still be unique to that table. 这将发生在服务器端,因此更新来自哪个客户端并不重要,它仍然是该表的唯一。 This stored procedure can then return the updated result set (if required) to the client so they can see the new PO #. 然后,此存储过程可以将更新的结果集(如果需要)返回给客户端,以便他们可以看到新的PO#。

That's the 20k foot view. 这是20公尺的视野。

Every time you do new Random() it is initialized . 每次执行新的Random()时都会初始化。 This means that in a tight loop you get the same value lots of times. 这意味着在紧密循环中,您可以多次获得相同的值。 You should keep a single Random instance and keep using Next on the same instance. 您应该保留一个Random实例并继续在同一个实例上使用Next。

//Function to get random number
private static readonly Random getrandom = new Random();
private static readonly object syncLock = new object();
public static int GetRandomNumber(int min, int max)
{
    lock(syncLock) { // synchronize
        return getrandom .Next(min, max);
    }
}

If you really want a random value, rather than return an int you could use a GUID. 如果你真的想要一个随机值,而不是返回一个int你可以使用GUID。 These are guaranteed to be unique: 这些保证是独一无二的:

A GUID is a 128-bit integer (16 bytes) that can be used across all computers and networks wherever a unique identifier is required. GUID是128位整数(16字节),可以在需要唯一标识符的所有计算机和网络中使用。 Such an identifier has a very low probability of being duplicated. 这种标识符具有非常低的重复概率。

Source 资源

The alternative is to keep a record of the last number used and simply increment it every time you need a new PO. 另一种方法是记录最后使用的数字,并在每次需要新PO时简单地增加它。 Make sure you put a lock around it so two processes don't try and increment it at the same time. 确保你锁定它,这样两个进程就不会尝试同时增加它。

  • don't use 0 for unknown values. 不要将0用于未知值。 Add back the unique constraint and use NULL to represent unknown/not-generated values. 添加唯一约束并使用NULL表示未知/未生成的值。 If you wish, display NULL as 0 to the user, but that is orthogonal to the issue. 如果您愿意,向用户显示NULL为0,但这与问题正交。
  • Don't use random to generate unique number and then try to insert, you'll complicate the logic unnecessarily with retries and regenerates. 不要使用随机生成唯一编号,然后尝试插入,您将不必要地重复逻辑重试和重新生成。 Use sequence generator like UPDATE seqnces SET sequence = sequence+1 OUTPUT INSERTED.sequence WHERE key = 'somekey' 使用序列生成器,如UPDATE seqnces SET sequence = sequence+1 OUTPUT INSERTED.sequence WHERE key = 'somekey'
  • Don't use random to generate business meaning values like purchase order numbers. 不要使用随机生成商业含义值,如采购订单编号。 Use a sequence generator, like above. 使用序列生成器,如上所述。

Updated 更新

With SQL Server 2008 and above you can have a unique filtered index to act as a constraint for everything not equal to 0: 使用SQL Server 2008及更高版本,您可以使用唯一的筛选索引作为不等于0的所有内容的约束:

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

Sort of like eating the cake and having it too... 有点像吃蛋糕和吃蛋糕......

If you really want a series of unique random numbers in a range (say 13287 to 21439) I would create a list of all the valid integers and then randomly swap them around. 如果你真的想要一系列范围内的一系列唯一随机数(比如13287到21439),我会创建一个包含所有有效整数的列表,然后随机交换它们。 Kind of a unsort if you like. 如果你愿意,那就是一种解脱。 This will give you a list of random, unique numbers. 这将为您提供随机,唯一数字的列表。

The trick is to save that list since if you really wanted random it would take some time to generate. 诀窍是保存该列表,因为如果你真的想要随机,那么生成需要一些时间。 I would then put that in a table so you could index through it from wherever you need it. 然后我会把它放在一个表中,这样你就可以从你需要的任何地方索引它。

From what you've wrote, it seems like you're heading the wrong way: You're confusing randomness with uniqueness. 从你所写的内容来看,你似乎走错了方向:你将随机性与独特性混为一谈。

You've removed a domain specific constraint, so that it will comply with the code you've wrote. 您已删除特定于域的约束,以便它符合您编写的代码。 If the value of the PONumber has no other relevance other than being unique, have the database generate it for you, or generate a GUID (if the database can't), which gives you some assurance the generated value will be unique. 如果PONumber的值除了唯一之外没有其他相关性,请让数据库为您生成它,或生成GUID(如果数据库不能),这可以保证生成的值是唯一的。

Otherwise, it's all up to you to do the hard work. 否则,完全取决于你的努力工作。 You'll have to generate a unique value, keeping in mind all threading and transactional issues. 您必须生成一个独特的值,记住所有线程和事务问题。

Like the previous posters, I would recommend a unique value over a random value. 像之前的海报一样,我会建议一个随机值的唯一值。 The sequence generator Remus suggests is likely the best approach. Remus建议的序列发生器可能是最好的方法。

However, if you really really need a random value, I would recommend using RNGCryptoServiceProvider over the Random class because it's more random. 但是,如果你真的真的需要一个随机值,我会建议使用RNGCryptoServiceProvider在Random类,因为它更随意。 Check out MSDN for more information . 查看MSDN以获取更多信息 There's a good StackOverflow question on RNGCryptoServiceProvider as well. 在RNGCryptoServiceProvider上也有一个很好的StackOverflow 问题

I think you have gone down the wrong path to start with and it's getting worse. 我认为你已经走错了道路,而且情况正在恶化。 There is no real business justification or requirements accompanying your stated problem, and thus it is difficult to see how our answers can satisfy your end goals. 您所声明的问题没有真正的商业理由或要求,因此很难看出我们的答案如何能够满足您的最终目标。

I think you should step back and clearly formulate your goals without respect to the curent physical implementation. 我认为你应该退后一步,明确制定你的目标,而不考虑实际的实施。

Typically, order systems do require unique PO, so you need to have a unique constraint on that. 通常,订单系统确实需要唯一的PO,因此您需要对其进行唯一约束。 Typically, systems do not store POs and "pre-POs" in the same way. 通常,系统不以相同的方式存储PO和“预PO”。 The "pre-POs" are usually called quotes or something similar, and they often have their own numbering system. “预PO”通常称为引号或类似的东西,它们通常有自己的编号系统。 Thus there usually is not a conflict in having NULL or 0 PO numbers, because there is not anything which is not a real PO stored with the real POs. 因此,在具有NULL或0个PO号码时通常不存在冲突,因为没有任何不是真实PO存储的真实PO。 Even in systems that want to store them together, they just go ahead and give them a number in the same sequence. 即使在想要将它们存储在一起的系统中,它们也只是继续并以相同的顺序给它们一个数字。

Also, an identity is perfectly fine to generate PO numbers. 此外,生成PO编号的身份完全正确。

How about pseudorandom numbers? 伪随机数怎么样? Granted, nearly every implementation of random numbers in language libraries are pseudorandom already, but there are algorithms you can implement that will give an appearance of randomness while maintaining uniqueness. 当然,几乎语言库中随机数的每一个实现都是伪随机数,但是你可以实现的算法会在保持唯一性的同时呈现随机性。

See the list of pseudorandom number generators for some. 请参阅一些伪随机数生成器列表 I like the idea of the linear feedback shift register to generate numbers that are nonsequential and have a defined period (ie, number of invocations between repeating numbers). 我喜欢线性反馈移位寄存器的想法,以产生非顺序的数字并具有定义的周期(即重复数字之间的调用次数)。

In situations like this, where there is a field or a set of fields that simply don't have a value because of the state of the entity that a record represents, I sometimes like to break the table into two separate tables that are related in a 1-to-1 relationship. 在这种情况下,由于记录所代表的实体的状态,有一个字段或一组字段根本没有值,我有时想把表分成两个相关的表。一对一的关系。

Let's suppose that your original table is called PurchaseOrder and has a structure that looks something like this: 假设您的原始表名为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
)

My suggestion would be to break that table apart so that it looks something like this: 我的建议是将该表拆开,使它看起来像这样:

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
)

Now your deal-specific information is in a separate table. 现在,您的特定交易信息位于单独的表格中。 Any purchase orders that don't yet have a deal set will simply not have a corresponding record in the PurchaseOrderDealInfo table. 任何尚未设置交易的采购订单都不会在PurchaseOrderDealInfo表中具有相应的记录。 Yes, you will need to join the tables together if you want to retrieve all of the information pertaining to a specific purchase order. 是的,如果要检索与特定采购订单相关的所有信息,则需要将表连接在一起。 However, you get some benefits: 但是,您可以获得一些好处:

  1. You can still apply a unique constraint to the PONumber column. 您仍然可以将唯一约束应用于PONumber列。

  2. You can take advantage of SQL Server's identity feature to generate your PONumber for you 您可以利用SQL Server的身份功能为您生成PONumber

  3. If you had any other deal-specific columns in your table that you made nullable simply because they wouldn't have a value until a deal was set, then once you move those columns into the PurchaseOrderDealInfo table you can set to not allow nulls (if appropriate). 如果你的表中有任何其他特定于交易的列只是因为在设置交易之前它们没有值,那么一旦将这些列移动到PurchaseOrderDealInfo表中,就可以设置为不允许空值(如果适当)。

  4. If you only want to retrieve purchase orders that have deals, then you can simply query the PurcahseOrderDealInfo table without having to specify any filter criteria. 如果您只想检索具有交易的采购订单,则只需查询PurcahseOrderDealInfo表,而无需指定任何过滤条件。 Of course, if you also need information from the PurchaseOrder table then you will need to do an inner join. 当然,如果您还需要PurchaseOrder表中的信息,那么您将需要进行内部联接。

Your autonumber PK in the database can be used as a unique PO number... just read and copy it when it becomes a "real" non-zero PO number. 您在数据库中的自动编号PK可用作唯一的采购订单编号...只需在它变为“真正的”非零采购订单编号时进行读取和复制。

This won't be "random" but it will be unique. 这不是“随机的”,但它将是独一无二的。

Now for the nerd answer: It's not possible for your computer to generate random numbers without some chaotic "random" seeds 现在对于书呆子的回答:你的计算机不可能在没有混乱的“随机”种子的情况下生成随机数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM