我首先使用Entity Framework代码来访问一组表,这些表的键将由默认约束中的基于int的SEQUENCE设置。 EF似乎无法处理这个问题,它坚持在插入后使用SCOPE_IDENTITY来填充整数键字段。
深入研究代码,看起来有点硬编码:
在页面的中间稍微查看IsValidScopeIdentityColumnType方法。如果此方法返回true,则使用SCOPE_IDENTITY()检索插入的Key值,否则将生成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' EDMType'我超越了我对EF映射真正起作用的真正理解。也许有某种方法可以使用用户定义的类型来欺骗它?但它确实是.NET方面的配置需要某种更新。
另请参阅同一文件中的UseGeneratedValuesVariable方法,了解其使用方法......
我不清楚为什么OUTPUT不会在这里全面使用 - 也许是性能?
答案 0 :(得分:5)
更新 - 仅支持数据库生成PK的身份
您可以创建标记为计算的键列,其中包含DataseGeneratedOption.Computed
。 (见DataseGeneratedOption enum)。
为了表明这一点,您可以使用DatabaseGeneratedAttribute装饰列,或者使用DbContext的OnModelCreating
方法中的流畅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; }
}
运行应用程序时,表格会正确创建。
当您尝试将第一个实体添加到实体集合并保存更改时,会出现问题。得到:Modifications to tables where a primary key column has property 'StoreGeneratedPattern' set to 'Computed' are not supported. Use 'Identity' pattern instead. Key column: 'Id'. Table: 'CodeFirstDatabaseSchema.ComputedKey'
。
这是EF的限制(直到6.1),只允许将整数类型或GUID作为PK的DB生成值。
<强> WORKAROUNDS 强>
<强>首先:强> 一种方法是使用DB上生成的列作为替代密钥。
从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命令来应用此自定义,则需要实现db初始化程序的Seed方法
<强>结论强>
此方案仅受到部分支持,因此您宁愿找到替代解决方案,除非之前的解决方案之一适合您。
请求此功能
如果您对此功能感兴趣,请转到实体框架功能建议,并为此投票:Allow using SQL Server 2012 sequence for generating primary key