可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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);
}
}
回答2:
This can also be done with attributes:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AddressID { get; set; }
回答3:
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 .
回答4:
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.
回答5:
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;
}
}
回答6:
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();
回答7:
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.