13

I am creating asp.net mvc4 sample.In this i created Id column as GUID in Sample table of datacontext.

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

This is entity table

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

Id pass 00000000-0000-0000-0000-000000000000.

How to set newid() to GUID and where i have to set.

Backs
  • 24,430
  • 5
  • 58
  • 85
user2285613
  • 199
  • 1
  • 8
  • 17
  • 1
    Are you sure you want to use a GUID as a primary key, you will get major performance issues due to fragmentation if the GUID is your clustered index. – Scott Chamberlain Aug 13 '13 at 04:46
  • yes i want GUID as primary key for some reason.How to set default value for GUId.Please help me. – user2285613 Aug 13 '13 at 04:49
  • "for some reason" does not sound like that good of a reason to me. You will have MUCH better performance off if you use a identity index and then you have an additional column with a unique non clustered index for the GUID column. – Scott Chamberlain Aug 13 '13 at 04:51
  • 1
    There have been measurements by now .The performance hit is definitely manageable. You can use a non-clustered primary key and/or NEWSEQUENTIALID() for guid generation. https://blogs.msdn.microsoft.com/sqlserverfaq/2010/05/27/guid-vs-int-debate/ – Volker Aug 26 '16 at 09:34
  • 1
    Solved this problem after long hours http://stackoverflow.com/a/42029852/7512541 – Vinu Das Feb 03 '17 at 17:37
  • @ScottChamberlain If you use NewID(), your point is fully correct. However, if you use NewSequentialID() instead, then you get to use GUIDs without fragmentation. It's a really cool idea, try it out. – Klom Dark Jul 21 '20 at 19:08

8 Answers8

14

I would recommend just using long for your ID type. It "just works" with and has some performance gains over GUID. But if you want to use a GUID, you should use a Sequential GUID and set it in the constructor. I would also make ID a private setter:

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);
        }
    }
Community
  • 1
  • 1
Paul
  • 12,392
  • 4
  • 48
  • 58
  • 1
    1.) Why is a sequential GUID better? 2.) What is the "Comb" in `GuidComb`? 3.) Why `0x76c` instead of simply `1900`? – Sinjai Mar 06 '18 at 04:07
  • 9
    Sequential GUID is a stupid idea. The whole point of GUID is it's such a large number you're guaranteed it's unique across all other GUIDs in the whole world when it's randomly selected. – binderbound Jul 03 '18 at 05:29
  • 2
    @binderbound It's NOT a stupid idea. The reason for using sequential GUID is that pure GUIDs are fully random. Using fully random anything (wherether GUID, int, etc) ends up effectively unsortable, so your indexes end up horribly fragmented and pointless, everything will end up needing a full table scan. Using Sequential GUID means that each one is bigger than the last one, so easily sortable and no fragmentation. This is for DB use only, anywhere else makes no sense to use Sequential GUID, but with a DB, it's an extremely intelligent idea. – Klom Dark Jul 21 '20 at 19:06
  • 1
    @klom-dark - if you really need it I guess you're right, but most of the time using GUID as an index is the wrong choice, because you don't have that much data, and you're fritting away memory for no reason. I agree with "long" being the better choice. – binderbound Feb 17 '21 at 04:01
10

This can also be done with attributes:

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AddressID { get; set; }
TombMedia
  • 1,962
  • 2
  • 22
  • 27
  • For me it doesn't works with Computed option. The Identity option works settings a default value in the SQL Database -> (newid()) – Ivan-San Aug 09 '19 at 21:18
6

If we ignore the politics around if this is a good idea or not, then the answer by @TombMedia is most likely what you are looking for.

If however, you need to add a new column to an existing table and want to specify newId() to be used for the default value because the field is not nullable then use this in your migration class:

AddColumn(
    "dbo.Samples",
    "UUID", 
    c => c.Guid(nullable: false, defaultValueSql: "newId()")
);

Note: this is an old question that is still relevant in EF6 and ranks high when looking for assistance on how to use newId inside EF migrations which is why this answer was added.

Chris Schaller
  • 13,704
  • 3
  • 43
  • 81
  • 1
    I would also remove the cluster from the index it creates too, put the cluster on a field that lends itself to indexing. `.PrimaryKey(t => t.MemberID, clustered: false)` – TombMedia Oct 17 '18 at 20:43
5

I encountered the same problem with Nlog logging to database . What I did is to purposely open the migration file and did the following changes

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

the identity parameter actually created the table with defaultvalue as newsequentialid() in the table .

Joy
  • 6,438
  • 8
  • 44
  • 75
  • Upvote for this answer. Because `newsequentialid()` is then implemented on the database. Say, if someone adds a new record by directly working on the table, it won't fail with a duplicate Guid error. – Blaise Dec 09 '14 at 20:24
2

The answer of Paul is right but the implementation of the Sequential Guid can be improved. This implementation of sequential guid increments more often and prevents same numbers if created on the same server.

To prevent link rot, the 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;
    }
}
Alex Siepman
  • 2,499
  • 23
  • 31
2

Since Entity Framework Core 5.0 you can override OnModelCreating() in ApplicationDbContext and write the following to specify any kind of complex default value by using T-SQL, for example, NEWID() or any T-SQL formula:

            modelBuilder.Entity<Sample>()
                .Property(sample => sample.ID)
                .HasDefaultValueSql("NEWID()");
Lucky Brain
  • 1,551
  • 12
  • 14
1

When using Entity Framework Core 2.1.1 I use:

[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UserId { get; set; }

Then in the migration, add in the defaultValueSql parameter as below:

migrationBuilder.CreateTable(
    name: "Users",
    columns: table => new
    {
         UserId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
         DisplayName = table.Column<string>(nullable: true)
    },
       constraints: table =>
    {
        table.PrimaryKey("PK_Users", x => x.UserId);
    });

This ensures that the sql server is responsible for generating a sequential guid which is going to be better than rolling your own.

If you do not want the downsides of using sequential guids you can use "newid()" instead.

0

I know that question is quite old, but if someone has such problem I suggest such solution:

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

You can get newid from SQL database when your new object is creating. For me it works. :) (but I don't know it is good practice)

How use it:

var myNewGuidValue = GetNewId();
Monic
  • 726
  • 10
  • 31