C# 首先更改EF5代码中的列默认值
我试图使用CF为现有数据库构建一个模型。我有一列忘记设置一个正常的默认值。我不想改变初始迁移的纯度,我只是想创建另一个迁移(这就是迁移的目的,对吗?:) 但这会产生C# 首先更改EF5代码中的列默认值,c#,entity-framework-5,entity-framework-migrations,C#,Entity Framework 5,Entity Framework Migrations,我试图使用CF为现有数据库构建一个模型。我有一列忘记设置一个正常的默认值。我不想改变初始迁移的纯度,我只是想创建另一个迁移(这就是迁移的目的,对吗?:) 但这会产生列,该列已绑定了默认值。SQL Server错误 如何使用CF迁移更改默认值?或者,如何简单地删除默认值(然后用不同的值重新创建) 编辑: 以下是生成的SQL语句: ALTER TABLE [Config] ADD CONSTRAINT DF_DefaultTaxPerDollar DEFAULT 0.087 FOR [Default
列,该列已绑定了默认值。
SQL Server错误
如何使用CF迁移更改默认值?或者,如何简单地删除默认值(然后用不同的值重新创建)
编辑:
以下是生成的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()
方法与一些受post启发的复杂Sql结合使用。问题源于这样一个事实:SQLServer使用约束来实现默认值(哦!我多么怀念MySQL!),并为约束生成一个名称。因此,Code First团队无法简单地更改或删除/重新创建默认值。以下是一个受其启发的解决方案。这不是一种优雅的方法,但对我来说很有效
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不存在且不起作用时才重新创建UDF。我想每次重新创建它都会更加健壮 删除由Entity Framework for 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);
}
Guid用于生成唯一的变量名,以防在一次迁移中删除多个约束。您能发布生成的SQL吗?是的,这是我的观点。我希望迁移只添加约束,而不检查/删除现有约束。我认为这可能被认为是一个bug。你能提供你的解决方案作为答案吗?可以-只要我确定:)我很确定这会起作用,但由于实际的SQL是由AlterColumnOperation对象构建的,然后一次发送到服务器,我的自定义SQL必须很好地处理所有生成的SQL,事实证明这有点棘手。当我让它工作时将发布。仅供参考,这应该在E6中固定(请参见)+1,但是
ALTER TABLE[{1}]…
中的方括号应该被删除。例如,在调用DropDefaultConstraint(“Sales.Orders”,…)
时,它们会导致架构限定表名出错。如果我的containtname包含字符“.”,则会导致错误。所以我把这一行“EXECUTE('ALTER TABLE{1}DROP CONSTRAINT'+{0})”,改为“EXECUTE('ALTER TABLE{1}DROP CONSTRAINT['+{0}+'])”,行得通。@heavenwing只是想感谢您的提醒,它帮助我在代码中解决了这个问题。
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));