2010-06-17 22 views
5
public int GenPurchaseOrderNum() 
{ 
    Random random = new Random(); 
    _uniqueNum = random.Next(13287, 21439); 
    return UniqueNum; 
} 

quité restricción única de la columna de PONumber en el PP porque un empleado sólo debe generar apartados de correos # cuando se establece el trato. De lo contrario, P.O. # tendría 0.¿Cómo puedo generar números aleatorios en Unqiue C#

P.O. El número solía tener una restricción única, esto obliga al empleado a generar P.O. en todos los casos, el db no arroja un error de restricción único.

Como eliminé la restricción única, cualquier cita no tiene P.O. llevará 0 valor. De lo contrario, se genera un valor único para P.O. #. Sin embargo, no tengo una restricción única en db que me dificulta saber si la aplicación generó P.O. # es único o no.

¿Qué debo hacer?

espero que mi pregunta es lo suficientemente

+5

¿Por qué el número debe ser aleatorio? –

+3

sí - ¿por qué al azar? me parece que quiere un número de pedido único, no uno al azar. Si eso es cierto, entonces debería ser fácil usar una tabla PO con una restricción única en la columna Id para generar números PO. – Cheeso

+2

Estos números son casi siempre secuenciales, ¿verdad? Si necesita alguna otra referencia única que no se pueda escribir por accidente, me gustaría ir con un Guid. –

Respuesta

11

Un GUID es un poco alto en el camino de la sobrecarga. Específicamente, parece que necesita un número legible para el PO #, lo que hace que una GUID no sea práctica. Estaría más inclinado a usar la siguiente situación.

  1. Elimina cualquier restricción NOT NULL que tengas en el campo.
  2. Tenga un procedimiento almacenado que use para crear un nuevo PO que deje el campo PO # NULL.Nulo es más apropiado en el caso descrito ya que en el mundo de DB NULL significa "desconocido" y dado que en realidad NO TIENE un PO #, ES desconocido.
  3. Utilice un procedimiento almacenado que actualice el campo cuando se complete la operación para incrementar al siguiente número de PO disponible. Esto sucederá en el servidor, por lo que no importa de qué cliente provenga la actualización, seguirá siendo exclusivo de esa tabla. Este procedimiento almacenado puede devolver el conjunto de resultados actualizado (si es necesario) al cliente para que puedan ver el nuevo PO #.

Esa es la vista de 20 k pie.

+0

Me parece bien, he usado este patrón antes, pero tengo algunas dudas sobre la sobrecarga de generar un nuevo Guid contra un bloqueo en una mesa. –

+0

Otra opción sería utilizar un campo de incremento automático y tener otro campo booleano que indique si se ha establecido el acuerdo. Suponiendo que 'un empleado solo debe generar P.O. # cuando se establece el acuerdo "no es una restricción * hard *, es decir ... –

+0

Diego, el programa almacenado no bloqueará toda la tabla. Simplemente generará un bloqueo de nivel de registro, aunque Danny puede tener un punto con respecto al requisito estricto de cuándo se debe generar el PO #. –

5

clara Si realmente desea un valor aleatorio, en lugar de devolver un int Se puede usar un GUID. Se garantiza que son únicos:

Un GUID es un número entero de 128 bits (16 bytes) que se puede usar en todas las computadoras y redes donde se requiere un identificador único. Tal identificador tiene una probabilidad muy baja de ser duplicado.

Source

La alternativa es mantener un registro del último número utilizado y simplemente se incrementará cada vez que necesita un nuevo PO. Asegúrese de colocar un candado alrededor para que dos procesos no intenten incrementarlo al mismo tiempo.

+0

GUID para una orden de compra #? ¿Por qué? –

+0

@BlueRaja - el OP pidió exclusividad garantizada, ofrecí dos soluciones. – ChrisF

5
  • No utilice 0 para valores desconocidos. Vuelva a agregar la restricción única y use NULL para representar valores desconocidos/no generados. Si lo desea, visualice NULL como 0 para el usuario, pero eso es ortogonal al problema.
  • No use aleatorio para generar un número único y luego intente insertar; complicará la lógica innecesariamente con reintentos y regenerará. Utilice el generador de secuencias como UPDATE seqnces SET sequence = sequence+1 OUTPUT INSERTED.sequence WHERE key = 'somekey'
  • No utilice el uso aleatorio para generar valores comerciales significativos, como los números de orden de compra. Use un generador de secuencia, como arriba.

Actualizado

Con SQL Server 2008 y por encima de usted puede tener una única filtered index para actuar como un obstáculo para todo no es igual a 0:

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

Algo así como comer la torta y tenerlo también ...

+0

"# no use 0 para valores desconocidos" - El problema es 0 se inserta en la columna PONumber de la aplicación. En el nivel de aplicación, tengo "int poNum;" variable que toma valor del recuadro de texto PONúmero, si el cuadro de texto no tiene ninguna cantidad de números pasará de 0 a db aunque yo no quiera eso. Voy a ir con el incremento – peace

2

Si realmente desea una serie de números aleatorios únicos en un rango (digamos 13287 a 21439) crearía una lista de todos los enteros válidos y luego los cambiaría aleatoriamente. Una especie de unsort si quieres. Esto le dará una lista de números aleatorios y únicos.

El truco está en guardar esa lista, ya que si realmente quisieras algo aleatorio, llevaría algo de tiempo generarlo. Luego pondría eso en una mesa para que pueda indexarlo desde donde lo necesite.

+0

Busca algoritmos de mezcla para generar la lista. –

0

Según lo que ha escrito, parece que va por el camino equivocado: está confundiendo la aleatoriedad con la singularidad.

Has eliminado una restricción específica del dominio, de modo que cumpla con el código que has escrito. Si el valor de PONumber no tiene otra relevancia que no sea única, haga que la base de datos la genere por usted, o genere un GUID (si la base de datos no puede), lo que le da cierta seguridad de que el valor generado será único.

De lo contrario, todo depende de usted para hacer el trabajo duro. Deberá generar un valor único, teniendo en cuenta todos los problemas de subprocesamiento y transacciones.

0

Como los carteles anteriores, recomendaría un valor único sobre un valor aleatorio. El generador de secuencias que Remus sugiere es probablemente el mejor enfoque.

Sin embargo, si realmente realmente necesita un valor aleatorio, recomendaría usar RNGCryptoServiceProvider en la clase Random porque es más aleatorio. Consulte MSDN para more information. También hay un buen StackOverflow question on RNGCryptoServiceProvider.

0

Creo que ha empezado por el camino equivocado y está empeorando. No existe una justificación comercial real ni requisitos que acompañen su problema declarado, por lo que es difícil ver cómo nuestras respuestas pueden satisfacer sus objetivos finales.

Creo que debe dar un paso atrás y formular claramente sus objetivos sin respeto a la implementación física actual.

Por lo general, los sistemas de pedido requieren un PO único, por lo que debe tener una restricción única sobre eso. Normalmente, los sistemas no almacenan PO y "pre-PO" de la misma manera. Los "pre-PO" generalmente se llaman citas o algo similar, y a menudo tienen su propio sistema de numeración. Por lo tanto, generalmente no hay conflicto al tener números NULL o 0 PO, porque no hay nada que no sea un PO real almacenado con los PO reales. Incluso en los sistemas que desean almacenarlos juntos, simplemente continúan y les dan un número en la misma secuencia.

Además, una identidad está perfectamente bien para generar números de PO.

0

¿Qué hay de los números pseudoaleatorios? De acuerdo, casi todas las implementaciones de números aleatorios en las bibliotecas de idiomas ya son pseudoaleatorias, pero existen algoritmos que puede implementar que darán una apariencia de aleatoriedad sin perder la exclusividad.

Vea el list of pseudorandom number generators para algunos. Me gusta la idea del linear feedback shift register para generar números que no son secuenciales y tienen un período definido (es decir, número de invocaciones entre números que se repiten).

0

En situaciones como esta, donde hay un campo o un conjunto de campos que simplemente no tienen un valor debido al estado de la entidad que representa un registro, a veces me gusta dividir la tabla en dos tablas separadas que están relacionados en una relación de 1 a 1.

Supongamos que la tabla original se llama PurchaseOrder y tiene una estructura que se ve algo como esto:

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 
) 

Mi sugerencia sería romper esa mesa aparte para que se vea algo como esto:

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 
) 

Ahora la información de su operación está en una tabla separada. Cualquier pedido de compra que aún no tenga un conjunto de transacciones simplemente no tendrá un registro correspondiente en la tabla PurchaseOrderDealInfo. Sí, deberá unir las tablas si desea recuperar toda la información relativa a una orden de compra específica. Sin embargo, obtiene algunos beneficios:

  1. Puede aplicar una restricción única a la columna PONumber.

  2. Usted puede tomar ventaja de la función de la identidad de SQL Server para generar su PONumber para usted

  3. Si tuviera cualquier otra columna específica para cada trato en su mesa que ha realizado anulable, simplemente porque no tendrían un valor hasta que se establezca una transacción, una vez que mueva esas columnas a la tabla PurchaseOrderDealInfo, puede establecer que no permita valores nulos (si corresponde).

  4. Si solo desea recuperar órdenes de compra que tienen ofertas, entonces simplemente puede consultar la tabla PurcahseOrderDealInfo sin tener que especificar ningún criterio de filtro. Por supuesto, si también necesita información de la tabla PurchaseOrder, deberá realizar una unión interna.

+0

Awesome advice ... – peace

0

Su PK autonumber en la base de datos se puede utilizar como un número de pedido único ... acaba de leer y copiar cuando se convierte en un número de pedido "real" no es cero.

Esto no será "aleatorio", pero será único.

Ahora la respuesta empollón: No es posible que su ordenador para generar números aleatorios sin algunas semillas caóticas "al azar"

11

Cada vez que haces nueva aleatorio() se inicializa. Esto significa que, en un ciclo cerrado, obtienes el mismo valor muchas veces. Deberías mantener una sola instancia Aleatoria y seguir usando Siguiente en la misma instancia.

//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); 
    } 
} 
Cuestiones relacionadas