11

festlegen Ich erstelle asp.net mvc4 sample.In diesem ich erstellt ID-Spalte als GUID in Beispieltabelle von datacontext.Wie Sie NewId() für GUID in Entity Framework

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

Dies ist Objekt-Tabelle

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

Id 00000000-0000-0000-0000-000000000000 passieren.

Wie setze ich newid() zu GUID und wo ich einstellen muss.

+1

Sind Sie sicher, dass Sie verwenden möchten Wenn Sie eine GUID als Primärschlüssel verwenden, treten aufgrund der Fragmentierung erhebliche Leistungsprobleme auf, wenn die GUID Ihr gruppierter Index ist. –

+0

Ja ich möchte GUID als Primärschlüssel aus irgendeinem Grund.Wie Standard-Wert für GUId.Please mir helfen. – user2285613

+0

Guid.NewGuid(); –

Antwort

13

Ich würde empfehlen, nur long für Ihren ID-Typ zu verwenden. Es funktioniert "einfach" und hat einige Leistungsvorteile gegenüber GUID. Wenn Sie jedoch eine GUID verwenden möchten, sollten Sie eine Sequential GUID verwenden und im Konstruktor festlegen. Ich würde auch ID einen private Setter machen:

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

Sequential 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.) Warum ist eine sequentielle GUID besser? 2.) Was ist der "Kamm" in "GuidComb"? 3.) Warum '0x76c' statt einfach' 1900'? – Sinjai

2

Die Antwort von Paul ist richtig, aber die Umsetzung der sequenziellen Guid kann verbessert werden. wird häufiger inkrementiert und verhindert gleiche Nummern, wenn sie auf demselben Server erstellt werden.

Um link rot zu verhindern, wird der Code:

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

traf ich das gleiche Problem mit Nlog zu Datenbank anzumelden. Was ich tat, ist absichtlich die Migrationsdatei zu öffnen und hat die folgenden

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

die Identität Parameter tatsächlich mit defaultvalue als newsequentialid() in der Tabelle ändert die Tabelle erstellt.

+0

Upvote für diese Antwort. Weil 'newsequentialid()' dann in der Datenbank implementiert wird. Angenommen, jemand fügt einen neuen Datensatz hinzu, indem er direkt an der Tabelle arbeitet, wird er nicht mit einem doppelten Guid-Fehler fehlschlagen. – Blaise

0

Ich weiß, diese Frage ist ziemlich alt, aber wenn jemand ein solches Problem hat schlage ich eine solche Lösung:

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

Sie können aus SQL-Datenbank newid erhalten, wenn Ihr neues Objekt erstellt wird. Für mich funktioniert es. :) (aber ich weiß nicht, es gute Praxis ist)

Wie es verwenden:

var myNewGuidValue = GetNewId(); 
+0

Das ist das Gleiche von var guid = Guid.NewGuid(); –

3

Dies auch mit Attributen durchgeführt werden kann:

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

Ich habe es berechnet, aber das half, danke! – Nick