如何将 nullable int 转换为 SQL Null 值?
How to convert nullable int to SQL Null value?
我需要使用 DataContext 的 ExecuteCommand 方法对具有多个基础表的视图执行更新。我之所以使用这种方法,是因为在对具有多个基础表的视图执行此类操作时,linqToSQL 的已知限制。
我现有的 SQL 语句类似于以下内容,我将 newFieldID 设置为空值只是为了 post 来说明问题。在应用程序中,newFieldID 被分配了一个传递的参数,实际上可以是一个整数值;但我的问题特定于提供的值是空类型的情况:
using (var _ctx = new MyDataContext())
{
int? newFieldID = null;
var updateCmd = "UPDATE [SomeTable] SET fieldID = " + newFieldID + "
WHERE keyID = " + someKeyID;
try
{
_ctx.ExecuteCommand(updateCmd);
_ctx.SubmitChanges();
}
catch (Exception exc)
{
// Handle the error...
}
}
此代码将失败的原因很明显,即在 newFieldID 为空值的情况下 updateCmd 将无法完成。那么如何用 SQL null 替换或转换 CLR null 值来完成语句?
我知道我可以将所有这些移动到存储过程,但我正在寻找现有方案的答案。我已经尝试使用 DBNull.Value 进行试验,但除了将其替换为要在语句中使用的 newFieldID 的挑战之外,简单地将其放入字符串会破坏语句的有效性。
另外,用单引号括起来:
var updateCmd = "UPDATE [SomeTable] SET fieldID = '" + DBNull.Value + "'
WHERE keyID = " + someKeyID;
将完成语句,但字段的值被转换为整数 0 而不是 SQL null。
那么在这种情况下,如何将 CLR null 或 nullable int 转换为 SQL Null 值?
通常,在使用存储过程或准备语句时,您使用参数来赋值。当您有 DbParameter
时,您可以将 null
或 DBNull.Value
分配给值 - 属性 或您的参数。
如果你想在语句中使用 null
作为文本,只需使用 SQL-关键字 NULL
var updateCmd = "UPDATE [SomeTable] SET fieldID = NULL WHERE keyID = " + someKeyID;
正确的方法:使用 ExecuteCommand
的 override 不仅接受命令文本,还接受参数数组并使用参数化查询而不是命令字符串连接:
var updateCmd = "UPDATE [SomeTable] SET fieldID = {0} WHERE keyID = {1}";
_ctx.ExecuteCommand(updateCmd, new [] {newFieldID, someKeyID});
它不仅会阻止你 sql 注入,还会为你做以下事情(来自 MSDN 描述):
If any one of the parameters is null, it is converted to DBNull.Value.
尝试检查 newFieldID == null 并相应地更改语句。
类似下面的内容或使用单独的 if / else 语句。
var updateCmd = "UPDATE [SomeTable] SET fieldID =" + (newFieldID == null ? "null" : Convert.ToString(newFieldID)) + " WHERE keyID = " + someKeyID;
正如 Andy Korneyev 和其他人所指出的,参数化数组方法是最好的,并且可能是使用 Prepared 语句时更合适的方法。由于我使用的是 LinqToSQL,建议使用带有参数数组的第二个参数的 ExecuteCommand 方法,但它的使用有以下注意事项。
- 查询参数不能是 System.Nullable`1[System.Int32][] 类型(在这种情况下我试图解决的主要问题)
- 所有参数必须是同一类型
Shankar 的答案有效,但它很快就会变得非常冗长,因为参数的数量可能会增加。
因此,我解决该问题的方法涉及某种程度上混合使用 Andy 和 Shankar 的建议所推荐的参数,方法是创建一个辅助方法来处理空值,该方法将采用带参数的 SQL 语句映射和实际参数。
我的辅助方法是:
private static string PrepareExecuteCommand (string sqlParameterizedCommand, object [] parameterArray)
{
int arrayIndex = 0;
foreach (var obj in parameterArray)
{
if (obj == null || Convert.IsDBNull(obj))
{
sqlParameterizedCommand = sqlParameterizedCommand.Replace("{" + arrayIndex + "}", "NULL");
}
else
sqlParameterizedCommand = sqlParameterizedCommand.Replace("{" + arrayIndex + "}", obj.ToString());
++arrayIndex;
}
return sqlParameterizedCommand;
}
所以我现在可以使用具有潜在空值的参数执行我的语句,如下所示:
int? newFieldID = null;
int someKeyID = 12;
var paramCmd = "UPDATE [SomeTable] SET fieldID = {0} WHERE keyID = {1}";
var newCmd = PrepareExecuteCommand(paramCmd, new object[] { newFieldID });
_ctx.ExecuteCommand(newCmd);
_ctx.SubmitChanges();
这减轻了先前提到的带有参数数组的 ExecuteCommand 的两个限制。空值得到适当的翻译,对象数组可能会改变 .NET 类型。
我将 Shankar 的提议标记为答案,因为它激发了这个想法,但发布了我的解决方案,因为我认为它增加了更多的灵活性。
我需要使用 DataContext 的 ExecuteCommand 方法对具有多个基础表的视图执行更新。我之所以使用这种方法,是因为在对具有多个基础表的视图执行此类操作时,linqToSQL 的已知限制。
我现有的 SQL 语句类似于以下内容,我将 newFieldID 设置为空值只是为了 post 来说明问题。在应用程序中,newFieldID 被分配了一个传递的参数,实际上可以是一个整数值;但我的问题特定于提供的值是空类型的情况:
using (var _ctx = new MyDataContext())
{
int? newFieldID = null;
var updateCmd = "UPDATE [SomeTable] SET fieldID = " + newFieldID + "
WHERE keyID = " + someKeyID;
try
{
_ctx.ExecuteCommand(updateCmd);
_ctx.SubmitChanges();
}
catch (Exception exc)
{
// Handle the error...
}
}
此代码将失败的原因很明显,即在 newFieldID 为空值的情况下 updateCmd 将无法完成。那么如何用 SQL null 替换或转换 CLR null 值来完成语句?
我知道我可以将所有这些移动到存储过程,但我正在寻找现有方案的答案。我已经尝试使用 DBNull.Value 进行试验,但除了将其替换为要在语句中使用的 newFieldID 的挑战之外,简单地将其放入字符串会破坏语句的有效性。
另外,用单引号括起来:
var updateCmd = "UPDATE [SomeTable] SET fieldID = '" + DBNull.Value + "'
WHERE keyID = " + someKeyID;
将完成语句,但字段的值被转换为整数 0 而不是 SQL null。
那么在这种情况下,如何将 CLR null 或 nullable int 转换为 SQL Null 值?
通常,在使用存储过程或准备语句时,您使用参数来赋值。当您有 DbParameter
时,您可以将 null
或 DBNull.Value
分配给值 - 属性 或您的参数。
如果你想在语句中使用 null
作为文本,只需使用 SQL-关键字 NULL
var updateCmd = "UPDATE [SomeTable] SET fieldID = NULL WHERE keyID = " + someKeyID;
正确的方法:使用 ExecuteCommand
的 override 不仅接受命令文本,还接受参数数组并使用参数化查询而不是命令字符串连接:
var updateCmd = "UPDATE [SomeTable] SET fieldID = {0} WHERE keyID = {1}";
_ctx.ExecuteCommand(updateCmd, new [] {newFieldID, someKeyID});
它不仅会阻止你 sql 注入,还会为你做以下事情(来自 MSDN 描述):
If any one of the parameters is null, it is converted to DBNull.Value.
尝试检查 newFieldID == null 并相应地更改语句。 类似下面的内容或使用单独的 if / else 语句。
var updateCmd = "UPDATE [SomeTable] SET fieldID =" + (newFieldID == null ? "null" : Convert.ToString(newFieldID)) + " WHERE keyID = " + someKeyID;
正如 Andy Korneyev 和其他人所指出的,参数化数组方法是最好的,并且可能是使用 Prepared 语句时更合适的方法。由于我使用的是 LinqToSQL,建议使用带有参数数组的第二个参数的 ExecuteCommand 方法,但它的使用有以下注意事项。
- 查询参数不能是 System.Nullable`1[System.Int32][] 类型(在这种情况下我试图解决的主要问题)
- 所有参数必须是同一类型
Shankar 的答案有效,但它很快就会变得非常冗长,因为参数的数量可能会增加。
因此,我解决该问题的方法涉及某种程度上混合使用 Andy 和 Shankar 的建议所推荐的参数,方法是创建一个辅助方法来处理空值,该方法将采用带参数的 SQL 语句映射和实际参数。
我的辅助方法是:
private static string PrepareExecuteCommand (string sqlParameterizedCommand, object [] parameterArray)
{
int arrayIndex = 0;
foreach (var obj in parameterArray)
{
if (obj == null || Convert.IsDBNull(obj))
{
sqlParameterizedCommand = sqlParameterizedCommand.Replace("{" + arrayIndex + "}", "NULL");
}
else
sqlParameterizedCommand = sqlParameterizedCommand.Replace("{" + arrayIndex + "}", obj.ToString());
++arrayIndex;
}
return sqlParameterizedCommand;
}
所以我现在可以使用具有潜在空值的参数执行我的语句,如下所示:
int? newFieldID = null;
int someKeyID = 12;
var paramCmd = "UPDATE [SomeTable] SET fieldID = {0} WHERE keyID = {1}";
var newCmd = PrepareExecuteCommand(paramCmd, new object[] { newFieldID });
_ctx.ExecuteCommand(newCmd);
_ctx.SubmitChanges();
这减轻了先前提到的带有参数数组的 ExecuteCommand 的两个限制。空值得到适当的翻译,对象数组可能会改变 .NET 类型。
我将 Shankar 的提议标记为答案,因为它激发了这个想法,但发布了我的解决方案,因为我认为它增加了更多的灵活性。