C# 如何使用DBNull.Value清晰快速地参数化空字符串
我厌倦了编写以下代码:C# 如何使用DBNull.Value清晰快速地参数化空字符串,c#,.net,sql-server,naming-conventions,C#,.net,Sql Server,Naming Conventions,我厌倦了编写以下代码: /* Commenting out irrelevant parts public string MiddleName; public void Save(){ SqlCommand = new SqlCommand(); // blah blah...boring INSERT statement with params etc go here. */ if(MiddleName==null){ myCmd.Parameters.
/* Commenting out irrelevant parts
public string MiddleName;
public void Save(){
SqlCommand = new SqlCommand();
// blah blah...boring INSERT statement with params etc go here. */
if(MiddleName==null){
myCmd.Parameters.Add("@MiddleName", DBNull.Value);
}
else{
myCmd.Parameters.Add("@MiddleName", MiddleName);
}
/*
// more boring code to save to DB.
}*/
所以,我写了这个:
public static object DBNullValueorStringIfNotNull(string value)
{
object o;
if (value == null)
{
o = DBNull.Value;
}
else
{
o = value;
}
return o;
}
// which would be called like:
myCmd.Parameters.Add("@MiddleName", DBNullValueorStringIfNotNull(MiddleName));
如果这是一个很好的方法,那么您建议使用什么方法名称?DBNullValuerStringNotNull有点冗长和混乱。
我也对完全缓解这个问题持开放态度。我很乐意这样做:
myCmd.Parameters.Add("@MiddleName", MiddleName==null ? DBNull.Value : MiddleName);
但这不起作用,因为“运算符”不能应用于“string”和“System.DBNull”类型的操作数
如果重要的话,我可以使用C#3.5和SQL Server 2005。将您的任何一个值转换为
对象,它将编译
myCmd.Parameters.Add("@MiddleName", MiddleName==null ? (object)DBNull.Value : MiddleName);
是的,我们都喜欢做myCmd.Parameters.Add(“@MiddleName”,MiddleName??DBNull.Value”)代码>。或者更好的是,让奇怪的SqlClient层理解,在添加参数时,CLRnull
应该映射到DBNull.Value
。不幸的是.Net类型的系统关闭了第一个备选方案,而SqlClient的实现关闭了第二个备选方案
我会使用一个众所周知的函数名,比如or。任何数据库开发人员都会在瞬间识别出他们所做的事情,仅从名称就可以了。就我个人而言,这就是我使用扩展方法所做的事情(确保它进入一个静态类)
那你就有了
myCmd.Parameters.Add("@MiddleName", MiddleName.GetStringOrDBNull());
我宁愿给你两个完全不同的建议:
使用ORM。有很多非侵入式ORM工具
为构建命令编写自己的包装器,具有更清晰的界面。比如:
public class MyCommandRunner {
private SqlCommand cmd;
public MyCommandRunner(string commandText) {
cmd = new SqlCommand(commandText);
}
public void AddParameter(string name, string value) {
if (value == null)
cmd.Parameters.Add(name, DBNull.Value);
else
cmd.Parameters.Add(name, value);
}
// ... more AddParameter overloads
}
如果将AddParameter
方法重命名为justAdd
,则可以非常灵活地使用它:
var cmd = new MyCommand("INSERT ...")
{
{ "@Param1", null },
{ "@Param2", p2 }
};
我建议使用可为null的属性,而不是公共字段和“AddParameter”方法(不知道这段代码是优化的还是正确的,我不知道):
@大卫:谢谢你的建议。下面的方法非常有效
MiddleName ?? (object)DBNull.Value
使用SqlString.Null
而不是DBNull.Value
,可以避免显式转换为对象
:
MiddleName ?? SqlString.Null
int、datetime等有相应的类型。下面是一段代码片段,还有几个示例:
cmd.Parameters.AddWithValue("@StartDate", StartDate ?? SqlDateTime.Null);
cmd.Parameters.AddWithValue("@EndDate", EndDate ?? SqlDateTime.Null);
cmd.Parameters.AddWithValue("@Month", Month ?? SqlInt16.Null);
cmd.Parameters.AddWithValue("@FormatID", FormatID ?? SqlInt32.Null);
cmd.Parameters.AddWithValue("@Email", Email ?? SqlString.Null);
cmd.Parameters.AddWithValue("@ZIP", ZIP ?? SqlBoolean.Null);
我根本不会编写null实例-如果值为null,请从insert语句中省略。但这不起作用。-请具体说明,为什么人们应该猜测?@Andrey:他的语句不会编译(编译器会说DBNull
和string
之间没有隐式转换)。@OMG:理论上很好,但很少有人会根据特定参数是否为null编写不同的insert语句。它增加了大量维护开销,但实际效益很小或根本没有(当然,除了能够利用列默认值之外)。@OMG,它能快多少(说真的,我不熟悉.net和SQL Server的通信方式)?有了TCP,我知道对于如此小的数据包,大部分时间都会花在RTT上。有很好的理由说明null
没有映射到DBNull.Value
。也就是说,它强制您为每个参数指定一个值,即使该“值”是数据库空值??对于这个特定的环境,值可能很好,你必须从编译器的角度考虑这个问题:那个表达式的返回类型是什么?编译器是否应该寻找最常见的祖先,即使它是对象
?也许我不清楚“CLR类型系统”是什么意思:无法建立表达式(type1??type2)
的编译时类型。我们说的是同一件事。我喜欢你还有一匹小马作为你的化身。@David:是的,我抓住它,让它保持不变:)甜蜜:MiddleName??(object)DBNull.Value
有效!或者更好的是公共静态只读对象DBNullValue=(object)DBNull.Value代码>带有MiddleName??DBNullValue
!你是我的英雄。啊,我还得再等3分钟才能接受你的回答。@David:太好了!甚至没有考虑过合并。我必须在我的代码中开始这样做。我考虑按您描述的那样缓存该值,但希望将代码保留在一行内。@davidmudoch:而不是MiddleName==null?(object)DBNull.Value:MiddleName
,也可以使用MiddleName??SqlString.Null代码>()。这在某些数据库上可能不起作用。我确实喜欢这个名称。所以这是+1。不过,我更喜欢接受答案的解决方案。:-)看看你是不是改变了主意,用100个if语句代替了100个三元运算符,我实际上用的是空合并运算符。您必须同意MiddleName??DBNullValue
非常简单。但是+1也用于您的注释。+1但是我更喜欢只对实际的null
值使用DBNull.Value
,并保留空字符串。我使用return(object)obj??DBNull.Value代码>在我的扩展方法版本中。我有很多“这样”的参数,在这种情况下,扩展方法就是最好的选择。谢谢value.HasValue不编译:HasValue用于可为null的对象类型,而不是对象类型
MiddleName ?? SqlString.Null
cmd.Parameters.AddWithValue("@StartDate", StartDate ?? SqlDateTime.Null);
cmd.Parameters.AddWithValue("@EndDate", EndDate ?? SqlDateTime.Null);
cmd.Parameters.AddWithValue("@Month", Month ?? SqlInt16.Null);
cmd.Parameters.AddWithValue("@FormatID", FormatID ?? SqlInt32.Null);
cmd.Parameters.AddWithValue("@Email", Email ?? SqlString.Null);
cmd.Parameters.AddWithValue("@ZIP", ZIP ?? SqlBoolean.Null);
myCmd.Parameters.Add("@MiddleName", MiddleName ?? (object)DBNull.Value);