C# 如何使用SQL Server和实体框架模拟序列(来自Oracle)的使用

C# 如何使用SQL Server和实体框架模拟序列(来自Oracle)的使用,c#,sql-server,entity-framework,sequences,C#,Sql Server,Entity Framework,Sequences,我们一直喜欢在Oracle数据库中使用序列,以便在整个数据库中创建全局唯一的主键ID。因此,在使用SQL Server数据库时,我们将模拟相同的情况: CREATE TABLE MainSequence( Id int IDENTITY(1,1) CONSTRAINT pkMainSequence PRIMARY KEY ) 我正在尝试切换到实体框架,这对我来说是非常新的。似乎创建一个扩展方法来快速获取下一个可用的全局唯一Id并不重要 public static int GetNext

我们一直喜欢在Oracle数据库中使用序列,以便在整个数据库中创建全局唯一的主键ID。因此,在使用SQL Server数据库时,我们将模拟相同的情况:

CREATE TABLE MainSequence(
    Id int IDENTITY(1,1) CONSTRAINT pkMainSequence PRIMARY KEY
)
我正在尝试切换到实体框架,这对我来说是非常新的。似乎创建一个扩展方法来快速获取下一个可用的全局唯一Id并不重要

public static int GetNextId( this Entities db ) {
    var ms = new MainSequence();
    db.MainSequences.AddObject( ms );
    db.SaveChanges( SaveOptions.None );
    return ms.Id;
}
因为它是一个标识列,所以我所要做的就是向数据库中添加一个新对象并保存更改,以便用实际值更新Id属性。这个很好用。但在尝试将其用于外键相关表时,我似乎遇到了麻烦:

var dataId = db.GetNextId();
db.Datas.AddObject( Data.CreateData( dataId, someValueForThisColumn );
db.Caches.AddObject( 
                    Cache.CreateCache( db.GetNextId(),
                    DatabaseMethods.GetOrAddLocation( source.GetLocationText() ),
                    DateTime.Now,
                    dataId ) );
缓存表具有数据表的外键。当
SaveChanges()时之后立即调用,生成异常

System.Data.SqlClient.SqlException:违反主键约束“pkData”。无法在对象“dbo.Data”中插入重复键。重复的键值为(78162)。 声明已终止


出于某种原因,新数据行似乎试图插入数据库两次,尽管我不知道为什么会这样。我已经确认,每次运行代码时,都会返回不同的mainsequenceid。似乎无论何时获得新ID都要调用
db.SaveChanges
是个问题,但是没有其他方法可以用真正的
int
填充,我不明白为什么这会是个问题。我做错了什么?

我的问题是行
db.SaveChanges(SaveOptions.None)。我使用此选项的原因是为了避免SaveOptions.AcceptAllChangesAfterSave,在我看来,通过从其他StackOverflow问题(无效或误解)收集的信息,我认为这将为我提供数据库事务的基本形式。我确实多次阅读了MSDN文档:

保存更改后,将调用AcceptAllChangesAfterSave()方法,该方法将重置ObjectStateManager中的更改跟踪


对我来说,这听起来很像交易变更跟踪。我认为,如果在保存调用中不接受更改,则在出现错误时,数据库“事务”将回滚(我后来发现情况并非如此)。相反,所有这些都是使ObjeCurror仍然认为更改是未保存的。因此,在下一次保存调用时,“未保存”更改将重新应用。Ta da,主键异常。这也解释了我的主序列跳过值的原因。

要么等待SQL Server 2012(它将完全支持
序列
db对象),或者使用
IDENTITY
列说明符,让SQL Server自动为您的表提供顺序ID-不要手动复制,这将是一场灾难……多年来,我们一直在SQL Server中复制顺序的使用,没有使用实体框架的问题。尽管我的问题有个标题,但我并不认为这个问题与复制序列有关。似乎我遇到的问题是对
SaveChanges(SaveOption)
方法的误解,我不允许多次调用它,或者需要以其他方式调用它。如果您尝试使用指定给
dataId
的固定值来测试它,它是否正常工作(
var-dataId=12345
)你喜欢它们的哪些方面——它们是全球独一无二的?如果是这样的话,为什么不生成顺序guid?@Sam.Rueby另一方面,我认为总是接受这样的观点是不明智的,即您尝试的方式是正确的。我不是针对这种情况说的,但一般来说,如果某件事情很难做到,可能有原因——一个更简单的解决方案不会让它变得低劣,特别是如果它仍然实现了你的所有目标。是的,确实,试着远离传递上下文,创建它,进行更改,然后启动一个保存更改调用。一旦你做了一些事情,导致你考虑操纵实体的变更状态,你就会自找麻烦