如何使用将动态填充的新字段进行迁移,例如通过将 EF 中的其他两个现有字段相乘
How can I make a migration with a new field that will be dynamically populated, for example by multiplying two other already existing fields in EF
我有实体 ProductItem 并且数据库已经通过使用此模板的迁移进行了更新:
public class ProductItem
{
public ProductItem()
{
Price = 0;
Discount = 0;
}
public string Name { get; set; }
public double Price { get; set; }
public int Discount { get; set; }
}
我的数据库中已经填充了一些实体。
我想再添加一个字段 TotalPrice:
public class ProductItem
{
public ProductItem()
{
Price = 0;
Discount = 0;
TotalPrice = 0;
}
public string Name { get; set; }
public double Price { get; set; }
public int Discount { get; set; }
public double TotalPrice { get; set; }
}
添加字段 TotalPrice 时,它将填充默认值,但我需要使用一个简单的公式 Price*(1 - Discount * 0.01) 来填充它每个字段。
这是我的新迁移代码,字段 TotalPrice:
public partial class _addedTotalPrice : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<double>(
name: "TotalPrice",
table: "ProductItems",
type: "float",
nullable: false,
defaultValueSql: "ROUND(Price*(1 - Discount * 0.01),0)");
migrationBuilder.UpdateData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "96ba8f64-053a-4574-a0bb-b73ecc88c761",
column: "ConcurrencyStamp",
value: "431db11e-8531-48bc-9483-5b13c0759d4e");
migrationBuilder.UpdateData(
table: "AspNetUsers",
keyColumn: "Id",
keyValue: "4c6e757b-ecb2-40a8-94fe-a2d3ecca28ca",
columns: new[] { "ConcurrencyStamp", "PasswordHash" },
values: new object[] { "390090d0-226e-43f6-af69-c3a139d602c0", "AQAAAAEAACcQAAAAEEcQUTyWcGF4TKR/qdtnDij7UjPt9NBtkwYw8WJX6CcVKnGBM8BuOj+YJVhYdgrA7A==" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "TotalPrice",
table: "ProductItems");
migrationBuilder.UpdateData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "96ba8f64-053a-4574-a0bb-b73ecc88c761",
column: "ConcurrencyStamp",
value: "734fc36f-7481-4782-942f-61ec56112815");
migrationBuilder.UpdateData(
table: "AspNetUsers",
keyColumn: "Id",
keyValue: "4c6e757b-ecb2-40a8-94fe-a2d3ecca28ca",
columns: new[] { "ConcurrencyStamp", "PasswordHash" },
values: new object[] { "3209c2fd-5fc0-46a9-9689-b73b3b7617af", "AQAAAAEAACcQAAAAEMLDk9vuX+uj98bjcAPnzRvfHw37gfJttkgeQ+vkpXzoIbOdf0tyNcJ38/uzuNCyhA==" });
}
}
}
我试着用 defaultValueSql 来做,但它不起作用:
defaultValueSql: "ROUND(Price*(1 - Discount * 0.01),0)");
和
defaultValueSql: "SELECT ROUND(Price*(1 - Discount * 0.01),0) FROM dbo.ProductItems");
如何解决?
这是终端:
PM> dotnet ef database update 20210205151510__addedTotalPrice
Build started...
Build succeeded.
The Entity Framework tools version '5.0.1' is older than that of the runtime '5.0.2'. Update the tools for the latest features and bug fixes.
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
ALTER TABLE [ProductItems] ADD [TotalPrice] float NOT NULL DEFAULT (ROUND(Price*(1 - Discount * 0.01),0));
Failed executing DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
ALTER TABLE [ProductItems] ADD [TotalPrice] float NOT NULL DEFAULT (ROUND(Price*(1 - Discount * 0.01),0));
Microsoft.Data.SqlClient.SqlException (0x80131904): РРјСЏ "Price" РЅРµ разрешено РІ данном контексте. Допустимыми выражениями являются константы, константные выражения Рё (РІ некоторых контекстах) переменные. Рмена столбцов РЅРµ разрешены.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite)
at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:9d817364-061a-4ade-b122-b50ca873140f
Error Number:128,State:1,Class:15
РРјСЏ "Price" РЅРµ разрешено РІ данном контексте. Допустимыми выражениями являются константы, константные выражения Рё (РІ некоторых контекстах) переменные. Рмена столбцов РЅРµ разрешены.
PM>
您可以创建一个 SQL 脚本来更新数据库中所有现有条目的值。
例如假设您使用脚本 'UpdateTotalPrice.sql' 在迁移文件夹旁边创建了一个名为 'Sql' 的文件夹,您可以从迁移脚本
中执行它
SqlFile(@"Sql\UpdateTotalPrice.sql");
只需确保在 .sql 文件中将 'Copy to output directory' 设置为 true。
看起来 TotalPrice 列应该是计算列。 link 将指导您如何执行此操作:
此外,table 列不允许出现在 defaultValueSql
参数中
我有实体 ProductItem 并且数据库已经通过使用此模板的迁移进行了更新:
public class ProductItem
{
public ProductItem()
{
Price = 0;
Discount = 0;
}
public string Name { get; set; }
public double Price { get; set; }
public int Discount { get; set; }
}
我的数据库中已经填充了一些实体。 我想再添加一个字段 TotalPrice:
public class ProductItem
{
public ProductItem()
{
Price = 0;
Discount = 0;
TotalPrice = 0;
}
public string Name { get; set; }
public double Price { get; set; }
public int Discount { get; set; }
public double TotalPrice { get; set; }
}
添加字段 TotalPrice 时,它将填充默认值,但我需要使用一个简单的公式 Price*(1 - Discount * 0.01) 来填充它每个字段。
这是我的新迁移代码,字段 TotalPrice:
public partial class _addedTotalPrice : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<double>(
name: "TotalPrice",
table: "ProductItems",
type: "float",
nullable: false,
defaultValueSql: "ROUND(Price*(1 - Discount * 0.01),0)");
migrationBuilder.UpdateData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "96ba8f64-053a-4574-a0bb-b73ecc88c761",
column: "ConcurrencyStamp",
value: "431db11e-8531-48bc-9483-5b13c0759d4e");
migrationBuilder.UpdateData(
table: "AspNetUsers",
keyColumn: "Id",
keyValue: "4c6e757b-ecb2-40a8-94fe-a2d3ecca28ca",
columns: new[] { "ConcurrencyStamp", "PasswordHash" },
values: new object[] { "390090d0-226e-43f6-af69-c3a139d602c0", "AQAAAAEAACcQAAAAEEcQUTyWcGF4TKR/qdtnDij7UjPt9NBtkwYw8WJX6CcVKnGBM8BuOj+YJVhYdgrA7A==" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "TotalPrice",
table: "ProductItems");
migrationBuilder.UpdateData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "96ba8f64-053a-4574-a0bb-b73ecc88c761",
column: "ConcurrencyStamp",
value: "734fc36f-7481-4782-942f-61ec56112815");
migrationBuilder.UpdateData(
table: "AspNetUsers",
keyColumn: "Id",
keyValue: "4c6e757b-ecb2-40a8-94fe-a2d3ecca28ca",
columns: new[] { "ConcurrencyStamp", "PasswordHash" },
values: new object[] { "3209c2fd-5fc0-46a9-9689-b73b3b7617af", "AQAAAAEAACcQAAAAEMLDk9vuX+uj98bjcAPnzRvfHw37gfJttkgeQ+vkpXzoIbOdf0tyNcJ38/uzuNCyhA==" });
}
}
}
我试着用 defaultValueSql 来做,但它不起作用:
defaultValueSql: "ROUND(Price*(1 - Discount * 0.01),0)");
和
defaultValueSql: "SELECT ROUND(Price*(1 - Discount * 0.01),0) FROM dbo.ProductItems");
如何解决? 这是终端:
PM> dotnet ef database update 20210205151510__addedTotalPrice
Build started...
Build succeeded.
The Entity Framework tools version '5.0.1' is older than that of the runtime '5.0.2'. Update the tools for the latest features and bug fixes.
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
ALTER TABLE [ProductItems] ADD [TotalPrice] float NOT NULL DEFAULT (ROUND(Price*(1 - Discount * 0.01),0));
Failed executing DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
ALTER TABLE [ProductItems] ADD [TotalPrice] float NOT NULL DEFAULT (ROUND(Price*(1 - Discount * 0.01),0));
Microsoft.Data.SqlClient.SqlException (0x80131904): РРјСЏ "Price" РЅРµ разрешено РІ данном контексте. Допустимыми выражениями являются константы, константные выражения Рё (РІ некоторых контекстах) переменные. Рмена столбцов РЅРµ разрешены.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite)
at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:9d817364-061a-4ade-b122-b50ca873140f
Error Number:128,State:1,Class:15
РРјСЏ "Price" РЅРµ разрешено РІ данном контексте. Допустимыми выражениями являются константы, константные выражения Рё (РІ некоторых контекстах) переменные. Рмена столбцов РЅРµ разрешены.
PM>
您可以创建一个 SQL 脚本来更新数据库中所有现有条目的值。
例如假设您使用脚本 'UpdateTotalPrice.sql' 在迁移文件夹旁边创建了一个名为 'Sql' 的文件夹,您可以从迁移脚本
中执行它SqlFile(@"Sql\UpdateTotalPrice.sql");
只需确保在 .sql 文件中将 'Copy to output directory' 设置为 true。
看起来 TotalPrice 列应该是计算列。 link 将指导您如何执行此操作:
此外,table 列不允许出现在 defaultValueSql
参数中