首先使用代码禁用整数主键上的标识(自动递增)
Posted
技术标签:
【中文标题】首先使用代码禁用整数主键上的标识(自动递增)【英文标题】:Disabling identity (auto-incrementing) on integer primary key using code first 【发布时间】:2020-05-29 09:50:07 【问题描述】:我在 ASP.NET MVC 3 应用程序中使用代码优先方法,模型中的所有整数主键 (public int Id get; set;
) 默认配置为具有自动递增功能的标识。如何禁用此功能并启用手动输入主键整数的方法?
实际情况是Id
整数具有特殊含义,因此我希望它们可以在创建时选择并在以后进行编辑。如果在创建时未给出整数,则它会自动递增,否则将使用指定的值,这将是理想的。但可编辑的主要字段是我的主要需求。有没有办法在 ASP.NET MVC 3 中优雅地做到这一点?
【问题讨论】:
【参考方案1】:使用这些数据注释选项:
[System.ComponentModel.DataAnnotations.KeyAttribute()]
[System.ComponentModel.DataAnnotations.DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]
【讨论】:
NAMESPACE CHANGE: 现在是 2015 年,这个答案的命名空间已经改变:[System.ComponentModel.DataAnnotations.KeyAttribute()] [System.ComponentModel.DataAnnotations.**Schema**.DatabaseGenerated( System.ComponentModel.DataAnnotations.**Schema**.DatabaseGeneratedOption.None)]
另外,“KeyAttribute”的“Attribute”部分是不需要的,没有理由不在顶部放置“Using”:using System.ComponentModel.DataAnnotations;using System.ComponentModel.DataAnnotations.Schema;[Key][DatabaseGenerated(DatabaseGeneratedOption.None)]
【参考方案2】:
您可以使用 FluentMapping:
modelBuilder.Entity<*entityname*>().Property(m => m.*fieldname*)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
【讨论】:
【参考方案3】:如果你想在 EntityFramework Core 2.0 中使用 fluent api,你可以这样写:
modelBuilder.Entity<*myEntity*>()
.Property(e => e.*myFieldname*)
.ValueGeneratedNever();
【讨论】:
【参考方案4】:使用属性:
public class MessageSubject
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id get; set;
public string Title get; set;
public string Comment get; set;
public bool BuildIn get; set;
【讨论】:
【参考方案5】:我刚刚安装了最新接受的 EntityFramework.dll 版本 5.0.0,我相信...
但是,我有一半的时间感到困惑,因为有一个运行时版本 v4.0.30319 和 4.4.0.0 版本,但是,我从网站上确定我 在我的搜索中被提及(它告诉我通过“包 管理器控制台”,您可以通过 VS 中的菜单访问该控制台 “工具|库包管理器|包管理器控制台”并键入 “PM>”提示“Install-Package EntityFramework [可选:版本 数字或 -Pre 表示最新的预发布(测试版)]") 5.0.0.
... ,并且您可以使用一个属性“System.CompnentModel.DataAnnotations.DatabaseGenerated(Computed, Identity or None) (previous version) or [...].Schema.DatabaseGenerated (latest version)” .所以要么使用这个属性,要么使用上面提到的流畅的映射思想(William Haack(由 Remo Gloor 编辑)),如果不是先编码(即改变生产),那么如上所述(由 Adam Tuliper)你将需要编写和执行一次性脚本以关闭身份插入。最重要的是,如果您不提供 ID,您可以通过在代码中(并记住多用户环境中的并发问题)或触发器中检索表上的 MAX(ID) + 1 来模拟身份插入。或者,如果您想堵住漏洞,正如表达式所示,您也可以在触发器中执行此操作,方法是拦截插入的行并检查是否设置了 ID 列,如果是,则继续插入,否则 先设置值。堵住漏洞的一种方法是使用那个技巧(我在一些我不记得的网站上看到过,所以我在这里猜了一点)你可以有效地从一些大表中进行反内连接,只需一个将单列行号添加到您的表中,以查找第一个可用的未使用标识号(即查找不是目标表成员的第一个行号)。
在 SQL Server 2005 及更高版本中:
CREATE TRIGGER updInsYourTable_PlugHolesOnIDIfNull
ON YourTable
FOR update, insert AS
BEGIN
DECLARE @ID INT
SELECT @ID = ID FROM INSERTED
IF @ID IS NULL
BEGIN
;WITH CTE_StagedNumbers AS
(
SELECT ROW_NUMBER() OVER (ORDER BY o.object_id) AS NextFreeIdentity
FROM ( SELECT object_id FROM sys.objects
-- UNION ALL
-- SELECT object_id FROM sys.objects
/* NB: Here if sys.objects is not larger enough say on a small schema
configured database then use a different table otherwise you can
always union all on the same table as many times as you want to
double, triple etc. its size. */
) o
)
UPDATE YourTable
SET ID = (
SELECT TOP 1 NextFreeIdentity
FROM CTE_StagedNumbers
WHERE NextFreeIdentity NOT IN (SELECT ID FROM YourTable)
)
WHERE ID IS NULL
END
END
GO
注意,CTE_StagedNumbers 不是必需的,它只是为了强调,主要技巧不一定是设置行号,但是,如果您要设置一个永久临时表(比如 StagedNumbers),只需没有自动标识的单个整数列(例如 NextFreeIdentity INT NOT NULL PRIMARY KEY),(注意:您的 ID 列的 YourTable 定义必须接受空值,因为我们使用的是后触发器)预先填充了相应的正整数值开始在 1 使用上述技术,然后完全删除 CTE,并将最终选择中的 CTE_StagedNumbers 替换为 StagedNumbers,这样效率最高。
【讨论】:
是的,触发器可能是一种方法,但直接访问和操作 SQL 数据库并不符合 MVC 框架的精神。【参考方案6】:如果这是数据库中的身份字段,则不能。好吧,您可以通过在数据库端设置身份插入关闭,但通过良好的做法,除非批量插入记录,否则您不应该这样做。如果您不希望将其作为身份,则在该列的数据库中将身份选项设置为 false。
【讨论】:
我使用的是代码优先的方法,这意味着数据库是从代码中生成的。我只提到了可以在数据库中看到的内容,因为我认为这是问题的根源。那么是否有用于禁用自动身份字段选项的数据注释? 那么在创建时使用代码优先方法将“SET IDENTITY_INSERT YourTableName OFF”(或某事)传递给数据库的最简单的方法是什么? 啊.. 代码优先。你在使用 [Key()] 吗?如果是这样,我认为您有些卡住了。我相信它适用于更简单的场景。在您的情况下,您不希望生成自动编号,但您仍然需要我假设的索引。不幸的是,Key() 字段没有给你这个控制,所以我会删除 Key 字段。如果您在任何地方都命名 Id 并且不使用 key() 属性,我会认真考虑将其更改为名为 Id 的数据库字段没有任何好处,并且当您跨表链接(fk 关系)时,说 Customer.Id = OtherTable 很奇怪.CustomerId 所以我会保持一致。 顺便说一下这里的一些 cmets:***.com/questions/5813190/… 我发现在数据库上关闭身份并不像更改表那么简单......但是这里有一个可行的简单解决方案:***.com/questions/7227812/…【参考方案7】:从外键表中删除Required属性对我来说是这样做的。
【讨论】:
以上是关于首先使用代码禁用整数主键上的标识(自动递增)的主要内容,如果未能解决你的问题,请参考以下文章
在不修改实体类(注释)或数据上下文(使用 fluentapi)的情况下禁用标识(自动递增)