- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我首先使用实体框架代码访问一组表,这些表的键将由默认约束中基于 int 的 SEQUENCE 设置。 EF 似乎无法处理此问题,它坚持在插入后使用 SCOPE_IDENTITY 来填充整数键字段。
深入研究代码,它看起来有点硬编码:
在页面的中间位置查看 IsValidScopeIdentityColumnType 方法。如果此方法返回 true,则使用 SCOPE_IDENTITY() 检索插入的键值,否则生成 OUTPUT 子句。 (Guid/uniqueidentifier 是那里的典型用例)。
// make sure it's a primitive type
if (typeUsage.EdmType.BuiltInTypeKind != BuiltInTypeKind.PrimitiveType)
{
return false;
}
// check if this is a supported primitive type (compare by name)
var typeName = typeUsage.EdmType.Name;
// integer types
if (typeName == "tinyint"
|| typeName == "smallint"
||
typeName == "int"
|| typeName == "bigint")
{
return true;
}
有什么方法可以让这个方法在整数字段上返回 false 吗?一旦我开始看到像“EDMType”这样的东西,我就超出了我对 EF 映射如何真正工作的真正理解。也许有某种方法可以使用用户定义的类型来欺骗它?但真正需要某种更新的是 .NET 端的配置。
另请参阅同一文件中的 UseGeneratedValuesVariable 方法以了解使用它的位置...
我不清楚为什么这里不全面使用 OUTPUT——也许是性能?
最佳答案
更新 - 数据库生成的 PK 仅支持身份
您可以创建一个标记为已计算的键列,它有一个 DataseGeneratedOption.Computed
。 (参见 DataseGeneratedOption enum)。
为了表明这一点,您可以用 DatabaseGeneratedAttribute 修饰该列,或在 DbContext 的 OnModelCreating
方法中使用 Fluent API,如下所示:
modelBuilder.Entity<EntityType>()
.Property(c => c.KeyColumn)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)
此示例代码与 EF6.1 完美配合
public class MyDbContext : DbContext
{
public IDbSet<ComputedKey> ComputedKeys { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Computed Key:
modelBuilder.Entity<ComputedKey>()
.HasKey(c => c.Id)
.Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
}
}
public class ComputedKey
{
public int Id { get; set; }
}
当您运行应用程序时,表格会正确创建。
当您尝试将第一个实体添加到实体集合并保存更改时,就会出现问题。您得到: 不支持对主键列的属性“StoreGeneratedPattern”设置为“Computed”的表进行修改。请改用“身份”模式。关键列:'Id'。表:“CodeFirstDatabaseSchema.ComputedKey”
。
这是 EF(直到 6.1)的一个限制,它只允许将整数类型或 GUID 作为 DB 生成的 PK 值。
变通办法
首先:一种是使用在数据库上生成的列作为替代键。
从 EF 6.1 开始,您可以创建 AK,使用如下属性装饰 AK 列:
[Index("MyIndex", unique: true)]
第二:使用序列的原因是定义种子和增量。如果这是您需要的,您可以像这样修改身份:
DBCC CHECKIDENT ('SchemaName.TableName', RESEED, 10);
这意味着下一次生成的身份值将为11,增量为1。
如果您需要使用不同的增量,则需要删除并重新创建标识列,以指示种子和增量。但是要做到这一点,您还需要删除并创建关联的 foreingk 键,因此这太难实现了。
第三:你可以使用触发器。在触发器内,您可以使用 SET IDENTITY_INSERT tableName ON/OFF
,但您可能会再次遇到问题,因为 @@identity
将不匹配。
注意:如果您需要运行自定义 SQL 命令来应用此自定义,则需要实现数据库初始化程序的 Seed 方法
结论
此方案仅部分受支持,因此您宁愿寻找替代解决方案,除非之前的解决方案之一适合您。
请求此功能
如果您对此功能感兴趣,请转到 Entity Framework 功能建议,并为此投票:Allow using SQL Server 2012 sequence for generating primary key
关于c# - 强制 EntityFramework 使用 OUTPUT 而不是 SCOPE_IDENTITY 来检索键值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23962690/
以下查询在事务中插入许多记录。我想获取新创建的增量标识符并在下一个 INSERT 中使用它陈述 对于单个记录,我可以使用如下 SELECT @new_emp_id= SCOPE_IDENTITY()
我有 PK,它是自增 key 。我需要将记录插入数据库,然后取回 PK 并在另一个插入中使用它。 但是我想在一笔交易中完成此操作。那可能吗。这个想法是,如果我必须做的任何更新/插入中出现问题,那么我可
好的,我有一个没有自然键的表,只有一个整数标识列作为它的主键。我想插入和检索标识值,但还要使用触发器来确保始终设置某些字段。最初,设计是使用而不是插入触发器,但这破坏了 scope_identity。
抱歉,如果这个问题很愚蠢,但我似乎找不到答案。刚开始使用 SQL。我正在阅读 Get the last inserted row ID (with SQL statement) 的答案,似乎 SCOP
浏览了一些答案,但似乎对我不起作用。 我需要返回一个表的 ID 字段,这样我就可以在程序的不同部分使用它,我试过使用 Convert.ToInt32(sqlComm.ExecuteScalar
我想在插入之前获取新的 id(Identity)。所以,使用这段代码: select SCOPE_IDENTITY() AS NewId from tblName 但是得到这个: 1- 空 2- 空
我有一个相当复杂的对象,包含嵌套的项目列表,每个项目都有自己的表格。 创建此对象时,出于性能原因,我想将它连同它的子对象及其所有后代一起插入到单个事务中。 我的表: Parent |Id| Has a
我创建了一个应该在一个中执行 2 个插入的存储过程 第一步,我想为每个插入创建一个新条目。 第二步我将从这个条目中获取创建的 Id 第三步我想从一个表中复制每个选择的多个条目并将它们插入到具有 Id
我有以下 SQL 代码用于将新记录插入我的数据库 DECLARE @CustomerID INT DECLARE @PropertyID INT BEGIN TRAN T1 INSERT IN
我一直在寻找高低问题的答案,并认为我将转向stackoverflow社区。由于以下错误,我一直在避免在SQL Server和nhibernate中使用类型标识ID字段字段:http://connect
我使用的是 SQL Server 2014。 我通过将所有物理地址列移动到专用地址表来对现有数据库进行非规范化,如下所示: 旧: Customers (CustomerId, AddressLine1
我有一个带有标识列的表,我想在 INSERT 之后获取其值。以下代码不使用参数,但运行良好: string query = "INSERT INTO aTable ([aColumn]) VALUES
当我尝试通过 SQL Server 获取插入数据库的最后一个 ID 时,它返回 __Page。这是我的代码: query = "INSERT INTO seekers(nam
我有一个存储过程,它首先将一些数据插入到临时表中,然后将一行插入到另一个表中。我在第二次插入后调用 Scope_Identity() 以获取新插入的记录 Identity。 如果第二次插入由于连接而没
我有一个表MyTable,我在那个表上有一个After trigger(On Insert)。 当我在 MyTable 上运行批量插入语句时,它会触发触发器以捕获插入的数据(即用于审计日志目的)。 我
我正在用 SQL server 写一个 SP ALTER PROCEDURE [dbo].[spAddUserBadge] AS BEGIN INSERT INTO dbo.SE_UserBa
我的存储过程是: ALTER PROCEDURE [dbo].[Insert_QuickLabDump] @Specimen_ID [varchar](50), @Client_Key
我正在尝试返回新创建行的 ID。我试过用 SCOPE_IDENTITY 来做,但它返回 3。我四处搜索,无法确定我做错了什么。 代码如下: " SelectCommand="SELEC
我遇到异常:“指定的转换无效”,这是代码 con.Open(); string insertQuery = @"Insert into Tender (Name, Name1, Name2) valu
我正在尝试执行一个简单的 INSERT 并返回标识(自动递增主键)。我试过了 cmd.CommandText = "INSERT INTO Prototype ( ParentID ) VALUES
我是一名优秀的程序员,十分优秀!