Изменение значений по умолчанию столбца в коде EF5
Я пытаюсь использовать CF для создания модели для существующей базы данных. У меня есть столбец, в котором я забыл установить нормальное значение по умолчанию. И вместо того, чтобы поставить под угрозу чистоту первоначальной миграции, изменив ее, я просто решил создать другую миграцию (это то, для чего миграции, верно? :)
public override void Up()
{
AlterColumn("Config", "DefaultTaxPerDollar", c => c.Decimal(nullable: false, precision: 19, scale: 5, defaultValue: 0.087m));
}
public override void Down()
{
AlterColumn("Config", "DefaultTaxPerDollar", c => c.Decimal(nullable: false, precision: 19, scale: 5, defaultValue: 0.0m));
}
но это производит Column already has a DEFAULT bound to it.
ошибка SQL Server.
как изменить значение по умолчанию с помощью миграции CF? Или, как просто удалить значение по умолчанию (а затем повторно создать его с другим значением)?
Edit:
вот сгенерированный SQL:
ALTER TABLE [Config] ADD CONSTRAINT DF_DefaultTaxPerDollar DEFAULT 0.087 FOR [DefaultTaxPerDollar]
ALTER TABLE [Config] ALTER COLUMN [DefaultTaxPerDollar] [decimal](19, 5) NOT NULL
Я думаю, что, возможно, нашел решение, чтобы использовать Sql()
метод с некоторым сложным SQL, вдохновленный этой пост. Проблема связана с тем, что SQL Server использует ограничения для реализации значений по умолчанию (OH! как я скучаю по MySQL!) с сгенерированным именем для ограничения. Поэтому код первой команды не смог просто измените или удалите/повторно создайте значение по умолчанию легко.
2 ответов
удаление ограничений по умолчанию, вызванных обратными миграциями, созданными Entity Framework для SQL Server
public static void DropDefaultConstraint(string tableName, string columnName, Action<string> executeSQL)
{
string constraintVariableName = string.Format("@constraint_{0}", Guid.NewGuid().ToString("N"));
string sql = string.Format(@"
DECLARE {0} nvarchar(128)
SELECT {0} = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'{1}')
AND col_name(parent_object_id, parent_column_id) = '{2}';
IF {0} IS NOT NULL
EXECUTE('ALTER TABLE {1} DROP CONSTRAINT ' + {0})",
constraintVariableName,
tableName,
columnName);
executeSQL(sql);
}
Это немного короче, но использование его.
DropDefaultConstraint(TableName, "DefaultTaxPerDollar", q => Sql(q));
Guid используется для создания уникального имени переменной, если вы собираетесь удалить несколько ограничений в одной миграции.
вот решение, которое было вдохновлено этот пост. Это не совсем элегантный метод, но он работает для меня.
public static void DropDefaultConstraint(string tableName, string columnName, Action executeSQL)
{
// Execute query that drops the UDF that finds the default constraint name
var query = @"
-- recreate UDF
if object_id('[dbo].[GetDefaultConstraintName]') is not null
begin
drop function [dbo].[GetDefaultConstraintName]
end
";
executeSQL(query);
// Execute query that (re)creates UDF that finds the default constraint name
query = @"
create function [dbo].[GetDefaultConstraintName] (
@TableName varchar(max),
@ColumnName varchar(max))
returns varchar(max)
as
begin
-- Returns the name of the default constraint for a column
declare @Command varchar(max)
select
@Command = d.name
from
((
sys.tables t join
sys.default_constraints d
on
d.parent_object_id = t.object_id) join
sys.columns c
on
c.object_id = t.object_id and
c.column_id = d.parent_column_id)
where
t.name = @TableName and
c.name = @ColumnName
return @Command
end
";
executeSQL(query);
// Execute query that actually drops the constraint
query = string.Format(@"
-- Use UDF to find constraint name
DECLARE @Constraint_Name VARCHAR(100)
SET @Constraint_Name = [dbo].GetDefaultConstraintName('{0}','{1}')
if LEN(@Constraint_Name) > 0
BEGIN
DECLARE @query VARCHAR(300)
SET @query = 'ALTER TABLE {0} DROP CONSTRAINT ' + @Constraint_Name
execute(@query)
END", tableName, columnName);
executeSQL(query);
}
и в вашей миграции вы можете назвать это так:
DropDefaultConstraint(TableName, "DefaultTaxPerDollar", q => Sql(q));
причина использования lamba заключается в том, что вы должны сделать три различных вызова Sql()
. Я никогда не мог заставить это работать как один длинный запрос-пробовал много комбинаций ключевого слова GO
во многих разных местах. Я также попытался изменить логику по первому запросу, чтобы UDF только воссоздавался, если он не существует, и он не работал. Я полагаю, что воссоздание его каждый раз более надежно в любом случае.