How to set NewId() for GUID in entity framework

后端 未结 7 1220
孤街浪徒
孤街浪徒 2020-12-06 01:43

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          


        
相关标签:
7条回答
  • 2020-12-06 02:13

    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 讨论(0)
  • 2020-12-06 02:14

    This can also be done with attributes:

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid AddressID { get; set; }
    
    0 讨论(0)
  • 2020-12-06 02:17

    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();
    
    0 讨论(0)
  • 2020-12-06 02:19

    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 .

    0 讨论(0)
  • 2020-12-06 02:19

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-06 02:25

    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);
            }
        }
    
    0 讨论(0)
提交回复
热议问题