Cly*_*yde 6 c# entity-framework
我首先使用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;
}
Run Code Online (Sandbox Code Playgroud)
有没有办法欺骗这个方法为整数字段返回false?一旦我开始看到像'EDMType'这样的东西,我就超出了我对EF映射真正起作用的真正理解.也许有一些方法可以使用用户定义的类型来欺骗它?但它确实是.NET方面的配置需要某种更新.
另请参阅同一文件中的UseGeneratedValuesVariable方法,了解其使用方法...
我不清楚为什么OUTPUT不仅仅是全面使用 - 也许是性能?
更新 - 仅支持DB生成PK的身份
您可以创建一个标记为计算的键列,其中包含一个DataseGeneratedOption.Computed.(请参阅DataseGeneratedOption枚举).
为了表明这一点,你可以使用DatabaseGeneratedAttribute来装饰列,或者在OnModelCreatingDbContext 的方法中使用流畅的API ,如下所示:
modelBuilder.Entity<EntityType>()
.Property(c => c.KeyColumn)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)
Run Code Online (Sandbox Code Playgroud)
此示例代码与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; }
}
Run Code Online (Sandbox Code Playgroud)
运行应用程序时,表格已正确创建.
当您尝试将第一个实体添加到实体集合并保存更改时,会出现问题.你得到: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)]
Run Code Online (Sandbox Code Playgroud)
第二: 使用序列的原因是定义种子和增量.如果这是你需要的,你可以像这样修改身份:
DBCC CHECKIDENT ('SchemaName.TableName', RESEED, 10);
Run Code Online (Sandbox Code Playgroud)
这意味着下一个生成的标识值将为11,增量将为1.
如果需要使用不同的增量,则需要删除并重新创建标识列,指示种子和增量.但是为了做到这一点,你还需要删除并创建相关的foreingk键,因此实现起来太难了.
第三:
你可以使用触发器.你可以使用触发器内部SET IDENTITY_INSERT tableName ON/OFF,但是你可能会因为@@identity不匹配而遇到问题.
注意:如果需要运行自定义SQL命令来应用此自定义,则需要实现db初始化程序的Seed方法
结论
此方案仅部分受支持,因此您宁愿找到替代解决方案,除非之前的解决方案之一适合您.
请求这个功能
如果您对此功能感兴趣,请转到实体框架功能建议,并为此投票:允许使用SQL Server 2012序列生成主键