2010-12-12 91 views
5

Necesito generar una identificación única de 8 dígitos en C#. En mi sitio, un usuario se registrará y necesito generar una identificación única para él en el código C# (no quiero esta lógica en DB), luego de insertar la identificación, debo guardarla en la base de datos.Generar identificador de uinque de 8 dígitos en C#

Editar: Necesito que los números se generen de forma aleatoria cada vez.

+5

¿Puedes explicar por qué estás en contra de hacer esto en la base de datos? – Oded

Respuesta

11

Aunque no 8 dígitos, que haría uso de un GUID para tal fin:

var id = Guid.NewGuid().ToString() 

De Wikipedia:

Idealmente, un GUID nunca será genera dos veces por cualquier computadora o grupo de computadoras en existencia. El número total de claves únicas (2^128 o 3.4 × 10^38 - en relación hay alrededor de 1,33 × 10^50 átomos en la tierra) es tan grande que la probabilidad de que se genere el mismo número dos veces es extremadamente pequeñas, y ciertos técnicas se han desarrollado para ayudar a asegurar que los números no se duplican

+2

'probabilidad de generar el mismo número dos veces es extremadamente pequeño' pero no 0 –

+2

Tiene razón, pero es completamente seguro usar GUID para este propósito. Microsoft incluso usa GUID como clave principal de la tabla de base de datos. –

2

¿Por qué no mantener el último número asignado y aumentarlo en 1 al asignar una nueva ID? Interlocked.Increment puede ser útil. Puede rellenar el número con ceros a la izquierda con los 8 dígitos. Usar int como tipo de respaldo debería ser suficiente.

Editar: si desea que el número de vistazo al azar, simplemente almacenar en la base de datos no los propios números secuenciales asignados, pero el uso de algunos biyectiva. Por ejemplo, puede almacenar 7461873*ID + 17845612 en su lugar. Esto garantiza la singularidad y se ve al azar.

Por cierto, esto es similar a como funcionan generalmente los generadores de números aleatorios (solo que no usan el número secuencial, sino el resultado del cálculo anterior).

+0

No aborda el deseo del OP de aleatoriedad, pero para cualquiera que busque números secuenciales como la sugerencia original de @ Vlad, algo como esto hará: 'private static int _sequentialNum = 0; cadena privada GetNextNumber() {return Interlocked.Increment (ref _sequentialNum) .ToString ("d8"); } ' El método Increment se ajusta a Int32.MaxValue, si te preocupan los negativos y los números tan grandes, entonces usa Interlocked.Exchange para restablecer a 0 según sea necesario. – Rory

3

Si no te importa que las identificaciones sean predecibles, aceptaré la sugerencia de Vlad.

De lo contrario, generaría un número aleatorio en el rango requerido y solo intente para insertarlo en la base de datos ... si obtiene una excepción debido a la restricción de exclusividad violada en la base de datos (y esa restricción absolutamente debería estar allí) luego intente de nuevo. Sigue intentándolo hasta que funcione o hayas dado varias vueltas. (Es muy poco probable que usted fallará 100 veces, por ejemplo - a menos que tengas un error en otro lugar, en cuyo caso es preferible a un bucle infinito una excepción.)

Así que esto no es generar el ID en la base de datos, pero está verificando la singularidad en la base de datos, que es, después de todo, la "fuente de verdad" definitiva.

Si no necesita identificadores generados criptográficamente de forma segura, simplemente usar Random.Next(100000000) le generará un valor en el rango [0, 99999999]. Si no desea ningún valor que requiera que los primeros 0 lleguen a 8 dígitos, simplemente use Random.Next(10000000, 100000000), que le dará un rango más pequeño de valores posibles, pero no tendrá que preocuparse de que tengan menos de 8 dígitos.

El uso de Random correctamente tiene algunos "errores" - vea mi article about it para más detalles.

+0

Si el número debe ser "impredecible", buscaría la solución combinada: mantenga el número "real" simplemente aumentado en 1 cada vez, y asócielo a una representación "impredecible" usando algún mapeo uno a uno de [ 0..99999999] en sí mismo. Un ejemplo de tal mapeo es 'x -> (N * x + M) mod 10^8', donde' gcd (N, 10^8) == 1) '. La ventaja de este enfoque no es necesario intentarlo. – Vlad

+0

@Vlad: Eso se basa en la seguridad por oscuridad, es decir, que su algoritmo no se conoce. –

+0

ningún generador aleatorio basado en código es verdaderamente aleatorio (excepto que utiliza algunos procesos físicos no disponibles para el análisis en línea), por lo que usar el generador de números aleatorios no garantiza una seguridad realmente mejor. – Vlad

1

Puede utilizar Random Class

Random r=new Rand(); 
int id; 
while((id=r.Next(10000000,99999999))!=someId); //check in database that Id is unique 

Siempre recuerda que no existe una técnica para generar un número aleatorio único sin comprobar los valores existentes en la base de datos de

debe tener alguna información con respecto a los valores anteriores

+0

¿por qué no? Mi respuesta da un ejemplo de cómo lograr esto sin consultar la base de datos. – Vlad

+1

@Vlad, me refiero a los valores anteriores y también debe recordar el valor anterior –

1

Puede intentar implementar un método que genere un número aleatorio, pero siempre debe verificar si ya está en la base de datos.

static void Main(string[] args) 
    { 
     HashSet<string> numbers = new HashSet<string>(); 

     for (int i = 0; i < 100; i++) 
     { 
      numbers.Add(GenerateRandomNumber(8)); 
     } 

     Console.WriteLine(numbers.Count == 100); 
     Console.ReadLine(); 
    } 

    static Random random = new Random(); 

    static string GenerateRandomNumber(int count) 
    { 
     StringBuilder builder = new StringBuilder(); 

     for (int i = 0; i < count; i++) 
     { 
      int number = random.Next(10); 
      builder.Append(number); 
     } 

     return builder.ToString(); 
    } 
1

uso secuencial GUID! Reduce la probabilidad de un choque donde las guids ya tienen una baja probabilidad de colisión y también significa que puede ordenar sus datos por el Guid, que representa el momento de la inserción.

[DllImport("rpcrt4.dll", SetLastError = true)] 
    static extern int UuidCreateSequential(out Guid guid); 

    public static Guid SequentialGuid() 
    { 
     const int rpcSOk = 0; 
     Guid guid; 

     return UuidCreateSequential(out guid) != rpcSOk ? Guid.NewGuid() : guid; 
    } 

Usted puede poner este método en la clase base de clientes, o de todas las entidades y tienen que genera automágicamente en el constructor de base en instatiation.

0

También puede usar mi generador de identidades. Pero lamentablemente no es un número entero. Asegúrese de tener una columna de ID sensible a mayúsculas y minúsculas en db, de lo contrario, cambie el rango de caracteres. El identificador es amigable para la url. En base a DateTime Ticks parcial (10 caracteres) y al azar parcial (6 caracteres). No es ordenable, por lo tanto, use la columna AddedDate para obtener una secuencia de fila. Utilice el tipo de columna varchar(16) y la intercalación SQL_Latin1_General_CP1_CS_AS.

public static class IdentifyGenerator 
{ 
    private static char[] sybmols = { 
          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
          'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 
         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
         }; 

    public static string WebHash() 
    { 
     int length = sybmols.Length; 
     ulong num = (ulong)DateTime.Now.Ticks; 

     string output = string.Empty; 
     ulong tmp = num; 
     ulong mod = 0; 
     while (tmp != 0) 
     { 
      mod = tmp % (ulong)length; 
      tmp = tmp/(ulong)length; 
      output = sybmols[mod] + output; 
     } 
     output += RandomString(6); 
     return output; 
    } 

    public static string RandomString(int length) 
    { 
     Stack<byte> bytes = new Stack<byte>(); 
     string output = string.Empty; 

     for (int i = 0; i < length; i++) 
     { 
      if (bytes.Count == 0) 
      { 
       bytes = new Stack<byte>(Guid.NewGuid().ToByteArray()); 
      } 
      byte pop = bytes.Pop(); 
      output += sybmols[(int)pop % sybmols.Length]; 
     } 
     return output; 
    } 
} 

Test Unit:

[TestClass] 
public class Code 
{ 
    [TestMethod] 
    public void IdentifyGeneratorTest() 
    { 
     var set = new HashSet<string>(); 
     for (int i = 1; i <= 1000000; i++) 
     { 
      var id = IdentifyGenerator.WebHash(); 
      if (!set.Add(id)) 
       Assert.Fail("IdentifyGenerator duplicate found"); 
     } 
    } 
} 

Buena suerte.

+0

¿por qué 'RandomString (6)'? también 'IdentifyGenerator.WebHash()' produce una cadena de longitud '16' no' 8'. –

Cuestiones relacionadas