asp.net-mvc 如何在实体框架中为 GUID 设置 NewId()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18200817/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set NewId() for GUID in entity framework
提问by user2285613
I am creating asp.net mvc4 sample.In this i created Id column as GUID in Sample table of datacontext.
我正在创建 asp.net mvc4 示例。在这个示例中,我在数据上下文示例表中创建了 Id 列作为 GUID。
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.
身通过 00000000-0000-0000-0000-000000000000。
How to set newid()to GUIDand where i have to set.
如何设置newid()到GUID哪里,我必须集中。
回答by Paul
I would recommend just using longfor 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 GUIDand set it in the constructor. I would also make ID a privatesetter:
我建议只使用long您的 ID 类型。它“仅适用于”并比 GUID 有一些性能提升。但是如果你想使用 GUID,你应该使用Sequential GUID并在构造函数中设置它。我也会让 ID 成为一个private二传手:
public class Sample
{
public Sample() {
ID = GuidComb.Generate();
}
[Required]
public Guid ID { get; private set; }
[Required]
public string FirstName { get; set; }
}
Sequential GUID
顺序 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);
}
}
回答by TombMedia
This can also be done with attributes:
这也可以通过属性来完成:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AddressID { get; set; }
回答by Joy
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
我在将 Nlog 记录到数据库时遇到了同样的问题。我所做的是故意打开迁移文件并做了以下更改
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 defaultvalueas newsequentialid()in the table .
identity 参数实际上使用表中的defaultvalueas创建newsequentialid()了表。
回答by Chris Schaller
If we ignore the politics around if this is a good idea or not, then the answer by @TombMediais most likely what you are looking for.
如果我们忽略这是否是一个好主意周围的,那么@TombMedia的答案很可能就是您正在寻找的。
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:
但是,如果您需要向现有表添加新列并希望指定 newId() 用于默认值,因为该字段不可为空,则在迁移类中使用它:
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.
注意:这是一个老问题,在 EF6 中仍然相关,并且在寻求有关如何在 EF 迁移中使用 newId 的帮助时排名很高,这就是添加此答案的原因。
回答by Alex Siepman
The answer of Paul is right but the implementation of the Sequential Guid can be improved. This implementation of sequential guidincrements more often and prevents same numbers if created on the same server.
Paul 的回答是对的,但是 Sequential Guid 的实现可以改进。如果在同一服务器上创建,则这种顺序 guid 的实现会更频繁地递增并防止相同的数字。
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;
}
}
回答by Monic
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)
创建新对象时,您可以从 SQL 数据库中获取 newid。对我来说它有效。:)(但我不知道这是一个好习惯)
How use it:
如何使用它:
var myNewGuidValue = GetNewId();
回答by user5580884
When using Entity Framework Core 2.1.1 I use:
使用 Entity Framework Core 2.1.1 时,我使用:
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UserId { get; set; }
Then in the migration, add in the defaultValueSql parameter as below:
然后在迁移中,添加 defaultValueSql 参数如下:
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.
这确保了 sql server 负责生成一个顺序 guid,这将比滚动你自己的更好。
If you do not want the downsides of using sequential guids you can use "newid()" instead.
如果您不希望使用顺序 guid 的缺点,您可以改用“newid()”。

