我正在实现'check'约束,它只是为每个约束列调用CLR函数。
每个CLR函数都是一行或两行代码,它们尝试构造与该列关联的用户定义的C#数据类的实例。例如,“Score”类有一个构造函数,当构造失败时(即当分数超出有效范围时)会抛出有意义的错误消息。
首先,您如何看待这种方法?对我而言,它将我的数据类型集中在C#中,使其在我的应用程序中可用,同时在数据库中强制执行相同的约束,因此它防止非程序员尝试制作的管理工作室中的无效手动编辑。它到目前为止运行良好,虽然更新程序集会导致禁用约束,需要重新检查所有约束(这是完全合理的)。我使用DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS
来确保所有表中的数据对启用和禁用的约束仍然有效,并在必要时进行更正,直到没有错误为止。然后我通过ALTER TABLE [tablename] WITH CHECK CHECK CONSTRAINT ALL
重新启用所有表的约束。 是否有重新启用的T-SQL语句,检查所有表上的所有检查约束,还是必须逐表重新启用它们?
最后,对于检查约束中使用的CLR函数,我可以:
我更喜欢2,因为我的函数更简单,没有错误代码,当有人使用管理工作室进行无效的列编辑时,他们将从CLR获得有意义的消息,如"Value for type X didn't match regular expression '^p[1-9]\d?$'"
而不是一些通用SQL像“违反约束”这样的错误。 允许CLR错误通过SQL Server是否有任何严重的负面后果,或者它是否与约束违规导致的任何其他插入/更新失败一样?
答案 0 :(得分:2)
例如,“Score”类有一个构造函数,当构造失败时(即当分数在有效范围之外时)会抛出有意义的错误消息。首先,您如何看待这种方法?
它让我有点担心,因为调用ctor需要内存分配,这是相对昂贵的。对于插入的每一行,您调用的是 - 仅用于其副作用。
同样昂贵也是例外。当你需要它们时它们很棒,但是你可以在ctor上下文中使用它们,但不能在检查环境中使用它们。
通过将检查作为类静态或自由函数存在,重构可以降低成本,然后检查约束和ctor都可以调用:
class Score {
private:
int score;
public:
static bool valid( int score ) {
return score > 0 ;
}
Score( int s ) {
if( ! valid( s ) ) {
throw InvalidParameter();
}
score = s;
}
}
检查约束调用Score :: valid(),不需要构造或异常。
当然,对于每一行CLR调用,您仍然有开销。这是否可以接受是你必须决定的。
是否有重新启用的T-SQL语句,检查所有表上的所有检查约束,还是必须逐表重新启用它们?
不,但你可以这样做来生成命令:
select 'ALTER TABLE ' || name || ' WITH CHECK CHECK CONSTRAINT ALL;'
from sys.tables ;
然后对数据库运行结果集。
OP的评论:
我为所有数据类型使用名为ConstrainedNumber和RegexConstrainedString的基类。我可以轻松地将这两个类的简单构造函数代码移动到您建议的单独的公共布尔值IsValueValid方法,并且可能会。
只有插入和更新才会发生CLR开销(和内存分配)。鉴于方法的简单性以及表更新的速率,我认为性能影响不会让我的系统担心。
我仍然希望为管理工作室用户提供的信息提出异常。我喜欢IsValueValid方法,因为它为我提供了不抛出错误的“选项”。在使用我的数据类型的应用程序中,我仍然可以通过构造实例来获得异常:)
我不确定我同意抛出异常,但是,“带回家的消息”是通过将问题分解为部分,您可以选择您愿意支付的部分,而无需付费你不使用的零件。你不使用的ctor,因为你只是叫它来获得副作用。所以我们分解了创建和检查。我们可以进一步分解投掷:
class Score {
private:
int score;
public:
static bool IsValid( int score ) {
return score > 0 ;
}
static checkValid( int score ) {
if( ! isValid( s ) ) {
throw InvalidParameter();
}
Score( int s ) {
checkValid( s ) ;
score = s;
}
}
现在,用户可以调用ctor,获取检查和可能的异常和构造,调用checkValid并获取检查和异常,或者isValid只获得有效性,仅为他所需的内容支付运行时成本。
答案 1 :(得分:-1)