11

Sto creando un esempio di asp.net mvc4. In questo ho creato la colonna Id come GUID nella tabella Sample di datacontext.Come impostare NewId() per GUID nell'entità framework

public class Sample 
{ 
    [Required] 
    public Guid ID { get; set; } 
    [Required] 
    public string FirstName { get; set; } 
} 

Questo è tabella di entità

CreateTable(
"dbo.Samples", 
c => new 
{ 
    ID = c.Guid(nullable: false), 
    FirstName = c.String(nullable: false)     
}) 
.PrimaryKey(t => t.ID); 

Id passare 00000000-0000-0000-0000-000000000000.

Come impostare newid() a GUID e dove devo impostare.

+1

Sei sicuro che si desidera utilizzare un GUID come chiave primaria, si verificheranno problemi di prestazioni importanti a causa della frammentazione se il GUID è l'indice cluster. –

+0

sì voglio GUID come chiave primaria per qualche motivo. Come impostare il valore predefinito per GUId.Please help me. – user2285613

+0

Guid.NewGuid(); –

risposta

13

Si consiglia di utilizzare solo long per il tipo di ID. Funziona "con" e ha alcuni guadagni in termini di prestazioni rispetto a GUID. Ma se si desidera utilizzare un GUID, è necessario utilizzare uno Sequential GUID e impostarlo nel costruttore. Vorrei anche fare un ID private setter:

public class Sample 
{ 
    public Sample() { 
     ID = GuidComb.Generate(); 
    } 
    [Required] 
    public Guid ID { get; private set; } 
    [Required] 
    public string FirstName { get; set; } 
} 

sequenziale GUID

public static class GuidComb 
    { 
     public static Guid Generate() 
     { 
      var buffer = Guid.NewGuid().ToByteArray(); 

      var time = new DateTime(0x76c, 1, 1); 
      var now = DateTime.Now; 
      var span = new TimeSpan(now.Ticks - time.Ticks); 
      var timeOfDay = now.TimeOfDay; 

      var bytes = BitConverter.GetBytes(span.Days); 
      var array = BitConverter.GetBytes(
       (long)(timeOfDay.TotalMilliseconds/3.333333)); 

      Array.Reverse(bytes); 
      Array.Reverse(array); 
      Array.Copy(bytes, bytes.Length - 2, buffer, buffer.Length - 6, 2); 
      Array.Copy(array, array.Length - 4, buffer, buffer.Length - 4, 4); 

      return new Guid(buffer); 
     } 
    } 
+0

1.) Perché è meglio un GUID sequenziale? 2.) Cos'è il "Pettine" in "GuidComb"? 3.) Perché '0x76c' invece di semplicemente' 1900'? – Sinjai

2

La risposta di Paolo è giusto, ma l'attuazione del sequenziale Guid può essere migliorata. This implementation of sequential guid aumenta più spesso e impedisce gli stessi numeri se creati sullo stesso server.

Per evitare link rot, il codice:

public class SequentialGuid 
{ 

    public DateTime SequenceStartDate { get; private set; } 
    public DateTime SequenceEndDate { get; private set; } 

    private const int NumberOfBytes = 6; 
    private const int PermutationsOfAByte = 256; 
    private readonly long _maximumPermutations = (long)Math.Pow(PermutationsOfAByte, NumberOfBytes); 
    private long _lastSequence; 

    public SequentialGuid(DateTime sequenceStartDate, DateTime sequenceEndDate) 
    { 
     SequenceStartDate = sequenceStartDate; 
     SequenceEndDate = sequenceEndDate; 
    } 

    public SequentialGuid() 
     : this(new DateTime(2011, 10, 15), new DateTime(2100, 1, 1)) 
    { 
    } 

    private static readonly Lazy<SequentialGuid> InstanceField = new Lazy<SequentialGuid>(() => new SequentialGuid()); 
    internal static SequentialGuid Instance 
    { 
     get 
     { 
      return InstanceField.Value; 
     } 
    } 

    public static Guid NewGuid() 
    { 
     return Instance.GetGuid(); 
    } 

    public TimeSpan TimePerSequence 
    { 
     get 
     { 
      var ticksPerSequence = TotalPeriod.Ticks/_maximumPermutations; 
      var result = new TimeSpan(ticksPerSequence); 
      return result; 
     } 
    } 

    public TimeSpan TotalPeriod 
    { 
     get 
     { 
      var result = SequenceEndDate - SequenceStartDate; 
      return result; 
     } 
    } 

    private long GetCurrentSequence(DateTime value) 
    { 
     var ticksUntilNow = value.Ticks - SequenceStartDate.Ticks; 
     var result = ((decimal)ticksUntilNow/TotalPeriod.Ticks * _maximumPermutations - 1); 
     return (long)result; 
    } 

    public Guid GetGuid() 
    { 
     return GetGuid(DateTime.Now); 
    } 

    private readonly object _synchronizationObject = new object(); 
    internal Guid GetGuid(DateTime now) 
    { 
     if (now < SequenceStartDate || now > SequenceEndDate) 
     { 
      return Guid.NewGuid(); // Outside the range, use regular Guid 
     } 

     var sequence = GetCurrentSequence(now); 
     return GetGuid(sequence); 
    } 

    internal Guid GetGuid(long sequence) 
    { 
     lock (_synchronizationObject) 
     { 
      if (sequence <= _lastSequence) 
      { 
       // Prevent double sequence on same server 
       sequence = _lastSequence + 1; 
      } 
      _lastSequence = sequence; 
     } 

     var sequenceBytes = GetSequenceBytes(sequence); 
     var guidBytes = GetGuidBytes(); 
     var totalBytes = guidBytes.Concat(sequenceBytes).ToArray(); 
     var result = new Guid(totalBytes); 
     return result; 
    } 

    private IEnumerable<byte> GetSequenceBytes(long sequence) 
    { 
     var sequenceBytes = BitConverter.GetBytes(sequence); 
     var sequenceBytesLongEnough = sequenceBytes.Concat(new byte[NumberOfBytes]); 
     var result = sequenceBytesLongEnough.Take(NumberOfBytes).Reverse(); 
     return result; 
    } 

    private IEnumerable<byte> GetGuidBytes() 
    { 
     var result = Guid.NewGuid().ToByteArray().Take(10).ToArray(); 
     return result; 
    } 
} 
5

ho incontrato lo stesso problema con NLog accedendo al database. Quello che ho fatto è quello di aprire volutamente il file di migrazione e ha fatto cambia il seguente

CreateTable(
"dbo.Samples", 
c => new 
{ 
    ID = c.Guid(nullable: false,identity:true), 
    FirstName = c.String(nullable: false) 
}) 
.PrimaryKey(t => t.ID); 

il parametro Identity effettivamente creato la tabella con defaultvalue come newsequentialid() nella tabella.

+0

Voto positivo per questa risposta. Perché 'newsequentialid()' viene quindi implementato nel database. Supponiamo che, se qualcuno aggiunge un nuovo record lavorando direttamente sul tavolo, non fallirà con un doppio errore di guida. – Blaise

0

so che domanda è abbastanza vecchio, ma se qualcuno ha un tale problema mi permetto di suggerire tale soluzione:

protected Guid GetNewId() 
{ 
    SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["YourConnectionString"].ConnectionString); 
    var query = "select newid()"; 
    conn.Open(); 
    SqlCommand com = new SqlCommand(query, conn); 
    var guid = new Guid(com.ExecuteScalar().ToString()); 
    conn.Close(); 
    return guid; 
} 

È possibile ottenere newid dal database SQL quando il nuovo oggetto sta creando. Per me funziona. :) (ma io non so che è buona pratica)

Come usarlo:

var myNewGuidValue = GetNewId(); 
+0

Questo è lo stesso di var guid = Guid.NewGuid(); –

3

Questo può essere fatto anche con gli attributi:

[Key] 
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
public Guid AddressID { get; set; } 
+0

L'ho impostato su computato ma questo ha aiutato grazie! – Nick