Asp.net mvc 如何在实体框架中为GUID设置NewId()
我正在创建asp.net mvc4示例。在此示例中,我在datacontext的示例表中创建了Id列作为GUIDAsp.net mvc 如何在实体框架中为GUID设置NewId(),asp.net-mvc,asp.net-mvc-3,asp.net-mvc-4,entity-framework-5,Asp.net Mvc,Asp.net Mvc 3,Asp.net Mvc 4,Entity Framework 5,我正在创建asp.net mvc4示例。在此示例中,我在datacontext的示例表中创建了Id列作为GUID public class Sample { [Required] public Guid ID { get; set; } [Required] public string FirstName { get; set; } } 这是实体表 CreateTable( "dbo.Samples", c => new { ID = c.G
public class Sample
{
[Required]
public Guid ID { get; set; }
[Required]
public string FirstName { get; set; }
}
这是实体表
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
如何将
newid()
设置为GUID
以及我必须设置的位置。我建议只使用long
作为ID类型。它“只工作”于GUID,并且比GUID有一些性能提升。但是,如果要使用GUID,应该使用并在构造函数中设置它。我也会让ID成为一个private
setter:
public class Sample
{
public Sample() {
ID = GuidComb.Generate();
}
[Required]
public Guid ID { get; private set; }
[Required]
public string FirstName { get; set; }
}
顺序GUID
Paul的答案是正确的,但是顺序Guid的实现可以改进。如果在同一台服务器上创建相同的数字,则增加的频率会更高,并防止出现相同的数字 为了防止这种情况,代码:
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;
}
}
公共类顺序GUID
{
public DateTime SequenceStartDate{get;private set;}
public DateTime SequenceEndDate{get;private set;}
私有常量int NumberOfBytes=6;
private const int PermutationsOfAByte=256;
private readonly long _maximumPermutations=(long)Math.Pow(PermutationsOfAByte,NumberOfBytes);
私有长序列;
公共序列GUID(DateTime sequenceStartDate、DateTime sequenceEndDate)
{
SequenceStartDate=SequenceStartDate;
SequenceEndDate=SequenceEndDate;
}
公共顺序GUID()
:这(新日期时间(2011年10月15日),新日期时间(2100年1月1日))
{
}
private static readonly Lazy InstanceField=new Lazy(()=>new SequentialGuid());
内部静态顺序GUID实例
{
得到
{
返回InstanceField.Value;
}
}
公共静态Guid NewGuid()
{
返回Instance.GetGuid();
}
公共时间跨度时间序列
{
得到
{
var ticksPerSequence=TotalPeriod.Ticks/_maximumPermutations;
var结果=新的时间跨度(ticksPerSequence);
返回结果;
}
}
公共时间跨度总周期
{
得到
{
var结果=SequenceEndDate-SequenceStartDate;
返回结果;
}
}
私有长GetCurrentSequence(日期时间值)
{
var ticksUntilNow=value.Ticks-SequenceStartDate.Ticks;
var结果=((十进制)ticksUntilNow/TotalPeriod.Ticks*_maximumPermutations-1);
返回(长)结果;
}
公共Guid GetGuid()
{
返回GetGuid(DateTime.Now);
}
私有只读对象_synchronizationObject=新对象();
内部Guid GetGuid(现在是日期时间)
{
如果(现在SequenceEndDate)
{
返回Guid.NewGuid();//超出范围,请使用常规Guid
}
var序列=GetCurrentSequence(现在);
返回GetGuid(序列);
}
内部Guid GetGuid(长序列)
{
锁定(_synchronizationObject)
{
if(sequence我在Nlog日志记录到数据库时遇到了同样的问题
CreateTable(
"dbo.Samples",
c => new
{
ID = c.Guid(nullable: false,identity:true),
FirstName = c.String(nullable: false)
})
.PrimaryKey(t => t.ID);
identity参数实际使用defaultvalue
作为newsequentialid()
在表中。我知道这个问题已经很老了,但如果有人有这样的问题,我建议这样的解决方案:
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;
}
在创建新对象时,您可以从SQL数据库中获取新ID。对我来说,它可以工作。:(但我不知道这是一种好的做法)
如何使用它:
var myNewGuidValue = GetNewId();
这也可以通过属性完成:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AddressID { get; set; }
如果我们忽略了周围的政治,不管这是不是一个好主意,那么答案很可能就是你在寻找的
但是,如果需要向现有表中添加一个新列,并且由于字段不可为Null而希望指定用于默认值的newId(),请在迁移类中使用此字段:
AddColumn(
"dbo.Samples",
"UUID",
c => c.Guid(nullable: false, defaultValueSql: "newId()")
);
注意:这是一个在EF6中仍然相关的老问题,在寻找如何在EF迁移中使用newId的帮助时排名很高,这就是为什么添加了这个答案
使用实体框架Core 2.1.1时,我使用:
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UserId { get; set; }
然后在迁移中,添加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);
});
migrationBuilder.CreateTable(
名称:“用户”,
列:表=>new
{
UserId=table.Column(nullable:false,defaultValueSql:“newsequentialid()”,
DisplayName=table.Column(可空:true)
},
约束:表=>
{
表.PrimaryKey(“PK_用户”,x=>x.UserId);
});
这确保了sql server负责生成顺序guid,这将比您自己的guid更好
如果您不想使用顺序GUID的缺点,可以改用“newid()”。是否确实要将GUID用作主键,如果GUID是聚集索引,则会由于碎片而导致严重的性能问题。是的,出于某种原因,我想将GUID用作主键。如何设置GUID的默认值。请帮助我。“出于某种原因"对我来说,这听起来不是一个很好的理由。如果使用标识索引,然后为GUID列添加一个具有唯一非聚集索引的附加列,则性能会好得多。到目前为止,已经有了度量。性能影响肯定是可管理的。您可以使用非聚集主键和/或NEWSEQUENTIALID()用于生成guid。在长时间投票后解决了此问题。因为newsequentialid()
随后在数据库上实现。例如,如果有人通过直接处理表来添加新记录,它不会因重复的guid错误而失败。这与var guid=guid.NewGuid()相同;1.)为什么顺序GUID更好?2.)在GuidComb
?3.)为什么0x76c
而不是简单的1900
?顺序GUID是一个愚蠢的想法。GUID的关键是它的数量如此之大,你可以保证它是正确的
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);
});