gpt4 book ai didi

sql-server - 在 Entity Framework 4.1 Code First 中手动生成主键的最佳方法是什么

转载 作者:行者123 更新时间:2023-12-03 10:05:26 25 4
gpt4 key购买 nike

在 Entity Framework 4.1 Code First 中手动生成主键的最佳方法是什么?

我正在编写 ASP.NET MVC 3 并使用存储库模式。

我目前使用以下代码按顺序生成 key :

'Code First Class
Public Class Foo
<Key()>
<DatabaseGenerated(DatabaseGeneratedOption.None)>
Public Property iId As Integer

Public Property sBar As String
End Class

'Context Class
Public Class FooBarContext : Inherits DbContext
Public Property Foos As DbSet(Of Foo)
End Class

'Get the current Id

'Part of code in repository that stores Entity Foo.
Dim iCurrId as Integer = (From io In context.Foo
Select io.iId()).Max

Dim iNewId as Integer = iCurrId + 1

Foo.iId = iNewId

我的看法是(但不太可能)两个(或更多)用户将尝试同时保存实体 Foo,因此将获得相同的 ID,插入将失败。

这是一个好方法,还是有更好的方法?

请注意,我不能(也不会)使用数据库生成的身份字段!

最佳答案

您的担忧是有道理的 - 在经常使用的网站中,这很可能发生,解决方案并不容易。您可以使用客户端 Guid如@Mikecito 所述,但它对性能有显着影响,我猜您不想使用它。

您目前这样做的方式非常糟糕,因为唯一的解决方案是将您的代码包装在单个可序列化事务中 - 事务必须同时包含选择 Id 和保存记录。这将访问您的 InventoryObjects顺序,因为每个 select max 将锁定整个表,直到事务提交 - 在插入事务期间没有其他人能够读取或写入数据到表中。在很少访问的站点中它不一定是一个问题,但在经常访问的站点中它可能不是问题。在您当前的设置中没有办法做到这一点。

部分改进是使用单独的表来保存最大值 + 存储过程以获取下一个值并在原子操作中递增存储值 - (它实际上模拟了来自 Oracle 的序列)。现在唯一的复杂问题是您是否需要没有间隙的序列。例如,如果保存新 InventoryObject 出现问题选定的 ID 将丢失,并且会在 ID 的序列中产生间隙。如果您需要没有间隙的序列,您必须再次使用事务来获取下一个 Id 并保存记录,但这次您将只锁定序列表中的单个记录。从序列表中检索 Id 应尽可能接近保存更改,以最大限度地减少序列记录被锁定的时间。

以下是 SQL Server 的序列表和序列过程示例:

CREATE TABLE [dbo].[Sequences]
(
[SequenceType] VARCHAR(20) NOT NULL, /* Support for multiple sequences */
[Value] INT NOT NULL
)

CREATE PROCEDURE [dbo].[GetNextSequenceValue]
@SequenceType VARCHAR(20)
AS
BEGIN
DECLARE @Result INT

UPDATE [dbo].[Sequences] WITH (ROWLOCK, UPDLOCK)
SET @Result = Value = Value + 1
WHERE SequenceType = @SequenceType

RETURN @Result
END

该表不需要首先通过代码映射 - 您永远不会直接访问它。您必须创建自定义数据库初始值设定项,以便在 EF 创建数据库时为您添加表和存储过程。您可以尝试与 described here 类似的方法.您还必须为具有起始值的序列添加初始化记录。

现在您只需要在保存记录之前调用存储过程来获取一个值:
// Prepare and insert record here

// Transaction is needed only if you don't want gaps
// This whole can be actually moved to overriden SaveChanges in your context
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
record.Id = context.Database.ExecuteStoreCommand("dbo.GetNextSequenceValue @SequenceType",
new SqlParameter("SequenceType", "InventoryObjects"));
context.SaveChanges();
}

关于sql-server - 在 Entity Framework 4.1 Code First 中手动生成主键的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5924258/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com