目前正在使用Entity Framework 5处理ASP.Net MVC 4应用程序。使用CodeFirst进行初始开发阶段。但现在已禁用自动迁移并直接使用SSMS设计新表并编写POCO。一切都很好。
最近,在Production中发现了一个奇怪的问题。其中一个最初设计的表中的记录跳过自动增量标识值超过900个数字。这在过去3个月内发生了3次。在本地调试应用程序但无法重现。没有观察到任何模式或趋势。
型号:
public class Enquiry
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public Int64 EnquiryId { get; set; }
[Required]
public int UserId { get; set; }
[Required]
public byte Bid { get; set; }
...
[Required]
public DateTime Created { get; set; }
[Required]
public DateTime Modified { get; set; }
}
public class EnquiryDetail
{
[Key]
public Int64 EnquiryId { get; set; }
[Required]
public int CreditScore { get; set; }
[Required]
public byte BidMode { get; set; }
public virtual Enquiry Enquiry { get; set; }
}
的DbContext:
public class EscrowDb : DbContext
{
public EscrowDb()
: base("name=DefaultConnection")
{
}
public DbSet<Enquiry> Enquiries { get; set; }
public DbSet<EnquiryDetail> EnquiryDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<EnquiryDetail>()
.HasRequired<Enquiry>(ed => ed.Enquiry)
.WithRequiredDependent(e => e.EnquiryDetail);
}
}
控制器:
[Authorize]
public class EnquiryController : Controller
{
private EscrowDb _db = new EscrowDb();
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(EnquiryViewModel core)
{
var enquiry = new Enquiry();
// Some code to set properties using passed ViewModel
...
var enquiryDetail = new EnquiryDetail();
// Some code to set properties using passed ViewModel
...
enquiry.EnquiryDetail = enquiryDetail;
_db.Enquiries.Add(enquiry);
_db.SaveChanges();
}
}
到目前为止,所有这些代码都运行良好,除了偶然跳过近1000个数字的大间隙的身份值。
有人遇到过这样的问题吗?请分享您的想法。
答案 0 :(得分:19)
如果你需要消除这些差距,你可能会失去运气。
在开发/测试新应用程序时,我自己就遇到了这个问题。我根据我读到的有关sql server 2012的内容,直观地了解sql azure中发生的事情。我无法找到有关sql azure的任何文档。
据我所知,这是一个IMO错误的功能。在Sql server 2012中,Microsoft添加了创建序列的功能。序列记录1000块中使用的值。所以假设您的序列正在进行中...... 1,2,3,4,5 ...然后您的sql server重新启动。那么序列已经保存了块1-1000已被使用的事实,所以它会跳到你的下一个1000 ....所以你的下一个值是1001,1002,1003,1004 ....这提高了性能使用序列时插入,但可能导致异常间隙。您的序列有一个解决方案。指定序列时,添加“NOCACHE”参数,以便一次不保存1000个块。 See here for more documentation.
如果这成为一个问题,那么Identity列似乎已被更改为使用相同的范例。因此,当您的服务器,或者在这种情况下,您的sql azure实例重新启动时,您可以在标识列中获得较大的间隙(1000),因为它将大块缓存为“已使用”。对于sql server 2012,有一个解决方案。您可以指定启动标志t272以将您的身份恢复为使用旧的sql server 2008 r2范例。问题是我不知道(可能不可能)如何在sql Azure中指定它。找不到文档。 See this thread for more details on sql server 2012.
Check the documentation of identity here in the msdn.特别是“服务器重启或其他故障后的连续值”部分。以下是它的说法:
服务器重启或其他故障后的连续值 -SQL Server 可能因性能原因和某些原因而缓存身份值 在数据库故障或服务器期间,分配的值可能会丢失 重新开始。这可能导致插入时身份值的缺口。如果 差距是不可接受的,然后应用程序应使用序列 生成器使用NOCACHE选项或使用自己的机制来实现 生成关键值。
因此,如果您需要具有连续值,则可以尝试使用nocache指定序列,而不是依赖于您的标识列。我自己没试过,but sounds like you'll have trouble getting this to work with entity framework.
很抱歉,如果这没有多大帮助,但至少它是您的体验的一些信息。
答案 1 :(得分:1)
尝试使用触发方法重新播种。我相信这应该解决它example of its use并在该链接上看到更多的解决方法。
USE [TEST]
CREATE TABLE TEST(ID INT IDENTITY(1,1),VAL VARCHAR(10))
CREATE TRIGGER TGR_TEST_IDENTITY ON TEST
FOR INSERT
AS
DECLARE @RESEEDVAL INT
SELECT @RESEEDVAL = MAX(ID) FROM TEST
DBCC CHECKIDENT('TEST', RESEED, @RESEEDVAL)
INSERT INTO TEST(VAL)VALUES('a')
SELECT * FROM TEST
因为&#39; DBCC CHECKIDENT&#39;现在您可以使用此link中的方法在Azure中不受支持 在那个链接中我得到了一些工作
然后当我使用
插入右键时再次返回身份设置identity_insert XXX关闭 - 这基本上打开IDENTITY
注意:对于正在接收大量插入请求的表而言,这不是一个好的解决方案,但对于寻找临时出路的人可能会有用
答案 2 :(得分:0)
似乎没有TF 272可以解决SQL Azure问题。我刚刚注意到2个表中的问题(999和1000的间隙),并且在检查两个表并检查插入的记录之前认为这是一个安全漏洞。 有关详细信息,请参阅this MS TechNet discussion的最后一项。有点重新保证,但看起来更像是一个错误,而不是一个功能。
答案 3 :(得分:0)
我也有这个问题,直到这次我找不到任何方式,似乎实体有一个bug或类似的东西。 我在互联网上搜索但没有任何内容