Code first Seed 方法中的错误 - 无法更新时间戳列
Error in Code first Seed method - Cannot update a timestamp column
我正在尝试将种子方法 运行 设置为 table(配置值)中的 create/update 值。初始 运行 成功并创建了 "TestSeed" 记录。但是更新会抛出以下错误。
这是我的种子方法,
context.SystemValues.AddOrUpdate(
sv => sv.Name,
new SystemValue { Name = "TESTSEED", Description = "Seed test1.", CreatedBy = "Sys", CreatedOn = DateTime.UtcNow, Value = "TESTSEED", ModifiedBy = "Sys", ModifiedOn = DateTime.UtcNow }
);
context.SaveChanges();
并且 AutomaticMigrationsEnabled = false
系统值class,
public partial class SystemValue
{
public int SystemValueId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public string Description { get; set; }
public System.DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public System.DateTime ModifiedOn { get; set; }
public string ModifiedBy { get; set; }
public byte[] Version { get; set; }
}
更新数据库出错,
PM> Update-Database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending explicit migrations.
Running Seed method.
System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Cannot update a timestamp column.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
为什么这个更新不起作用?我错过了什么吗?
编辑
我注意到的一件事是 RowVersion 字段不可空。我可以通过代码优先使它可以为空吗?
您需要告诉 EF 这是一个 timestamp
/ rowversion
列,这样它就不会尝试更新它。您可以通过在该列上添加 [Timestamp]
属性来执行此操作:
public partial class SystemValue
{
public int SystemValueId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public string Description { get; set; }
public System.DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public System.DateTime ModifiedOn { get; set; }
public string ModifiedBy { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
SQL服务器中的TIMESTAMP
/ ROWVERSION
列是一个特殊的列,只有SQL服务器内部可以更新——你作为数据库程序员只能阅读它出去。它跟踪行的版本,例如当你读取一行时,你可以记下它的版本,当你再次写入它时,你可以检查该行在你读取它之后是否已经被修改(那么该行版本列将有一个不同的比你读到的更有价值)
Marc_S 是正确的。但是在应用此更改时需要考虑一件小事。如果您将 "TimeStamp" 属性添加到现有版本字段,并且当我 运行 更新数据库时,它会给出另一个错误 - "Cannot update" 版本数据类型我必须先删除现有版本。因此,您需要先将其删除。
第 1 步 - 删除现有版本字段,添加新迁移并执行更新数据库。
第 2 步 - 使用 "TimeStamp" 添加版本字段并执行迁移和更新数据库。
如果您将 EF 数据库优先转换为 EF 代码优先,则可能会发生我提到的问题。当我最初这样做时,我错过了在迁移过程中测试这个系统值 class。
我正在尝试将种子方法 运行 设置为 table(配置值)中的 create/update 值。初始 运行 成功并创建了 "TestSeed" 记录。但是更新会抛出以下错误。
这是我的种子方法,
context.SystemValues.AddOrUpdate(
sv => sv.Name,
new SystemValue { Name = "TESTSEED", Description = "Seed test1.", CreatedBy = "Sys", CreatedOn = DateTime.UtcNow, Value = "TESTSEED", ModifiedBy = "Sys", ModifiedOn = DateTime.UtcNow }
);
context.SaveChanges();
并且 AutomaticMigrationsEnabled = false
系统值class,
public partial class SystemValue
{
public int SystemValueId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public string Description { get; set; }
public System.DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public System.DateTime ModifiedOn { get; set; }
public string ModifiedBy { get; set; }
public byte[] Version { get; set; }
}
更新数据库出错,
PM> Update-Database Specify the '-Verbose' flag to view the SQL statements being applied to the target database. No pending explicit migrations. Running Seed method. System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Cannot update a timestamp column. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
为什么这个更新不起作用?我错过了什么吗?
编辑
我注意到的一件事是 RowVersion 字段不可空。我可以通过代码优先使它可以为空吗?
您需要告诉 EF 这是一个 timestamp
/ rowversion
列,这样它就不会尝试更新它。您可以通过在该列上添加 [Timestamp]
属性来执行此操作:
public partial class SystemValue
{
public int SystemValueId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public string Description { get; set; }
public System.DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public System.DateTime ModifiedOn { get; set; }
public string ModifiedBy { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
SQL服务器中的TIMESTAMP
/ ROWVERSION
列是一个特殊的列,只有SQL服务器内部可以更新——你作为数据库程序员只能阅读它出去。它跟踪行的版本,例如当你读取一行时,你可以记下它的版本,当你再次写入它时,你可以检查该行在你读取它之后是否已经被修改(那么该行版本列将有一个不同的比你读到的更有价值)
Marc_S 是正确的。但是在应用此更改时需要考虑一件小事。如果您将 "TimeStamp" 属性添加到现有版本字段,并且当我 运行 更新数据库时,它会给出另一个错误 - "Cannot update" 版本数据类型我必须先删除现有版本。因此,您需要先将其删除。
第 1 步 - 删除现有版本字段,添加新迁移并执行更新数据库。
第 2 步 - 使用 "TimeStamp" 添加版本字段并执行迁移和更新数据库。
如果您将 EF 数据库优先转换为 EF 代码优先,则可能会发生我提到的问题。当我最初这样做时,我错过了在迁移过程中测试这个系统值 class。