2010-12-12 44 views
5

Devo generare un ID univoco di 8 cifre in C#. Sul mio sito un utente si registrerà e ho bisogno di generare un id univoco per lui nel codice C# (non voglio questa logica in DB), dopo aver inserito l'id ho bisogno di salvarlo nel database.Genera un ID uin di 8 cifre in C#

Modifica: Ho bisogno che i numeri vengano generati in modo casuale ogni volta.

+5

Puoi spiegare _perché _ sei contrario a farlo nel DB? – Oded

risposta

11

Anche se non 8 cifre, userei un GUID a tal fine:

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

Da Wikipedia:

Idealmente, un GUID non sarà mai generato due volte da qualsiasi computer o gruppo di computer esistente. Il numero totale di chiavi univoche (2^128 o 3.4 × 10^38 - in relazione ci sono circa 1,33 × 10^50 atomi terrestri) è così grande che la probabilità che lo stesso numero venga generato due volte è estremamente piccole, e alcuni tecniche sono state sviluppate per aiutare assicurare che i numeri non vengono duplicati

+2

'Probabilità che lo stesso numero sia generato due volte è estremamente piccolo' ma non 0 –

+2

Hai ragione - ma è completamente sicuro usare GUID per questo scopo. Microsoft utilizza persino GUID come chiave primaria della tabella del database. –

2

Perché non tenere solo l'ultimo numero assegnato e aumentarlo di 1 quando si assegna un nuovo ID? Interlocked.Increment potrebbe essere utile. È possibile eseguire il rilievo del numero con gli zeri a sinistra delle 8 cifre. Usare int come tipo di supporto dovrebbe essere sufficiente.

Edit: se si desidera che il numero di guardare casuale, basta memorizzare nel DB non i numeri sequenziali assegnati stessi, ma usare un po 'di corrispondenza biunivoca. Ad esempio, è possibile memorizzare 7461873*ID + 17845612. Questo garantisce l'unicità e sembra casuale.

A proposito, questo è simile a come i generatori di numeri casuali di solito funzionano (solo che non usano il numero sequenziale, ma piuttosto il risultato del calcolo precedente).

+0

Non si rivolge al desiderio dell'OP per casualità, ma per chiunque cerchi numeri sequenziali come il suggerimento originale di @ Vlad, qualcosa come questo farà: 'private static int _sequentialNum = 0; stringa privata GetNextNumber() {return Interlocked.Increment (ref _sequentialNum) .ToString ("d8"); } '. Il metodo Increment esegue il wrapping su Int32.MaxValue, se ti interessano i negativi e i numeri così grandi allora usa Interlocked.Exchange per reimpostare su 0 secondo necessità. – Rory

3

Se non ti dispiace che gli ID siano prevedibili, andrei con il suggerimento di Vlad.

Altrimenti, vorrei generare un numero casuale nell'intervallo richiesto e solo provare per inserirlo nel database ... se si ottiene un'eccezione a causa del vincolo di univocità che viene violato nel database (e tale vincolo assolutamente dovrebbe essere lì) quindi riprovare. Continua a provare fino a quando non funziona o hai girato un certo numero di volte. (È altamente improbabile che tu fallisca 100 volte per esempio - a meno che tu non abbia un bug altrove, nel qual caso un'eccezione è preferibile a un ciclo infinito.)

Quindi questo non è che genera l'ID nel database - ma sta verificando l'unicità nel database, che è dopo tutto l'ultima "fonte di verità".

Se non sono necessari ID crittografati generati in modo sicuro, utilizzare semplicemente Random.Next(100000000) genererà un valore nell'intervallo [0, 99999999]. Se non vuoi che i valori che hanno bisogno di portare gli 0 per arrivare a 8 cifre, usa semplicemente Random.Next(10000000, 100000000) che ti darà un intervallo più piccolo di valori possibili, ma non dovrai preoccuparti di avere meno di 8 cifre.

L'utilizzo di Random ha correttamente alcuni "trucchi" - vedere il mio article about it per ulteriori dettagli.

+0

Se il numero deve essere "imprevedibile", opterei per la soluzione combinata: mantieni il numero "reale" appena aumentato di 1 ogni volta e mappalo a una rappresentazione "imprevedibile" utilizzando una mappatura uno a uno di [ 0..99999999] su se stesso. Un esempio di tale mappatura è 'x -> (N * x + M) mod 10^8', dove' gcd (N, 10^8) == 1) '. Il vantaggio di questo approccio non è necessario provare. – Vlad

+0

@Vlad: questo si basa sulla sicurezza per oscurità, ad esempio che il tuo algoritmo non è noto. –

+0

nessun generatore casuale basato su codice è veramente casuale (tranne che utilizza alcuni processi fisici non disponibili per l'analisi online), quindi l'uso del generatore di numeri casuali non garantisce una sicurezza migliore. – Vlad

1

È possibile utilizzare Random Class

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

Ricordate sempre che non v'è alcuna tecnica per generare un numero casuale univoco senza controllare i valori esistenti nel database

è necessario disporre di alcune informazioni riguardanti i valori precedenti

+0

perché no? La mia risposta fornisce un esempio su come ottenere ciò senza interrogare il database. – Vlad

+1

@Vlad, voglio dire che i valori precedenti e devi anche ricordare per il valore precedente –

1

Si potrebbe provare a implementare un metodo che genera un numero casuale ma si deve sempre verificare se è già presente nel database.

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 sequenziale GUID! Riduce la probabilità di uno scontro in cui i guids hanno già una bassa probabilità di conflitto e significa anche che puoi ordinare i tuoi dati dal Guid, che rappresenta il tempo di inserimento.

[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; 
    } 

si può mettere questo metodo nella classe base per i clienti, o di tutte le entità e lo hanno generato automagicamente nel costruttore base su instatiation.

0

È anche possibile utilizzare il mio generatore di identificazione. Ma non è intero, sfortunatamente. Assicurati di avere la colonna ID maiuscole e minuscole in db altrimenti cambia l'intervallo di caratteri. L'identificatore è amico dell'URL. Basato su tick DateTime parziali (10 caratteri) e random parziale (6 caratteri). Non è ordinabile, quindi usa la colonna AddedDate per ottenere una sequenza di righe. Utilizzare il tipo di colonna varchar(16) e le regole di confronto 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; 
    } 
} 

Unit Test:

[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"); 
     } 
    } 
} 

Buona fortuna.

+0

perché 'RandomString (6)'? anche 'IdentifyGenerator.WebHash()' produce una stringa di lunghezza '16' non' 8'. –