使用linq将空值传递给ExecuteCommand()方法时遇到问题。我的代码类似于下面的代码:
public void InsertCostumer(string name, int age, string address)
{
List<object> myList = new List<object>();
myList.Add(name);
myList.Add(age);
myList.Add(address);
StringBuilder queryInsert = new StringBuilder();
queryInsert.Append("insert into Customers(name, address) values ({0}, {1}, {2})");
this.myDataContext.ExecuteCommand(queryInsert.ToString(), myList.ToArray());
}
但是,当参数为null(例如地址)时,我收到以下错误:“查询参数不能是'System.Object'类型。”
如果没有参数为null,则不会发生错误。我知道我的例子中的设计有点差,我只是创建了一个简化的例子来关注这个问题。有什么建议吗?
答案 0 :(得分:19)
这是一个已知错误,Microsoft不打算修复它......
解决方法是:
第二个不是一个好主意,因为它打开了你的SQL注入攻击,但它是一个快速黑客。
答案 1 :(得分:1)
他在LinqPad中围绕#1工作的一个例子。需要这个(对象)s ?? DBNull.Value
string s = null;
//ExecuteCommand("insert into T(C1) values({0})", s); //Exception
SqlCommand cmd= new SqlCommand(){
CommandText = "insert into T(C1) values(@P0)",
Connection = new SqlConnection(this.Connection.ConnectionString),
};
//cmd.Parameters.AddWithValue("@P0", s); //SqlException
cmd.Parameters.AddWithValue("@P0", (Object)s??DBNull.Value);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
Ts.OrderByDescending(t=>t.ID).Take(1).Dump();
答案 2 :(得分:0)
您是否尝试为那些为null的值分配值?含义(伪):
如果地址为空,则地址=“” 要么 如果年龄<&lt; 0然后年龄= 0
然后将其添加到myList
或者你总是可以使用三元运算符:
name = name.Length < 1 ? "" : name;
age = age < 1 ? Int32.MinValue : age;
然后将其添加到myList
答案 3 :(得分:0)
对我来说同样的问题。如此愚蠢的MS不解决这个问题。 这是我的解决方案,虽然我不支持所有参数类型,但是你明白了。我把它放在DataContext类中,所以它看起来像内置在Linq :)。
public int ExecuteCommandEx(string sCommand, params object[] parameters)
{
object[] newParams = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i] == null)
newParams[i] = "NULL";
else if (parameters[i] is System.Guid || parameters[i] is System.String || parameters[i] is System.DateTime)
newParams[i] = string.Format("'{0}'", parameters[i]);
else if (parameters[i] is System.Int32 || parameters[i] is System.Int16)
newParams[i] = string.Format("{0}", parameters[i]);
else
{
string sNotSupportedMsg = string.Format("Type of param {0} not currently supported.", parameters[i].GetType());
System.Diagnostics.Debug.Assert(false, sNotSupportedMsg);
}
}
return ExecuteCommand(string.Format(sCommand, newParams));
}
答案 4 :(得分:0)
我使用的是这样的东西(注意我正在使用SO“IDE”所以我不能,保证这将编译或正常工作,但你会得到这个想法)
public void InsertCostumer(string name, int age, string address)
{
List<object> myList = new List<object>();
myList.Add(name);
myList.Add(age);
myList.Add(address);
StringBuilder queryInsert = new StringBuilder();
queryInsert.Append("insert into Customers(name, age, address) values (");
int i = 0;
foreach (var param in myList.ToArray())
{
if (param == null)
{
queryInsert.Append("null, ");
myList.RemoveAt(i);
}
else
{
queryInsert.Append("{" + i + "}, ");
i++;
}
}
queryInsert.Remove(queryInsert.Length - 2, 2);
queryInsert.Append(")");
this.myDataContext.ExecuteCommand(queryInsert.ToString(), myList.ToArray());
}
答案 5 :(得分:0)
我制作了一个通用的ParamArray函数来传递我通常会传递给ExecuteCommand的parms。然后让它传回未解释的SQL parms和实际传入的对象列表。
Public Sub CommitRecords(ByVal InItems As List(Of Item)
Dim db As New DataContext(ConnectionString)
Try
For Each oItem In InItems
With oItem
Dim strParms As String = ""
Dim collParms = BuildExecuteCommandParms(strParms, .MapValue1, .MapValue2, .MapValue3, .MapValue4, .MapValue5, .MapValue6)
db.ExecuteCommand("Insert Into ItemTable (Value1, Value2, Value3, Value4, Value5, Value6)" & vbCrLf & _
"Values (" & strParms & ")", _
collParms.ToArray)
End With
Next
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Public Function BuildExecuteCommandParms(ByRef strParms As String, ByVal ParamArray InParms As Object()) As List(Of Object)
Dim i As Integer = 0
Dim collOutParms As New List(Of Object)
For Each oParm In InParms
If i <> 0 Then strParms &= ", "
If oParm Is Nothing Then
strParms &= "NULL"
Else
strParms &= "{" & i & "}"
collOutParms.Add(oParm)
End If
i += 1
Next
Return collOutParms
End Function
答案 6 :(得分:0)
我经常使用这种东西,不理想但如果你被卡住了就会完成它
if (myObject != null)
{
foreach (var p in ct.GetType().GetProperties())
{
if (p.GetValue(myObject , null) == null)
{
if (p.PropertyType == typeof(string))
{
p.SetValue(myObject , "Empty", null);
}
if (p.PropertyType == typeof(int))
{
p.SetValue(myObject , 0, null);
}
if (p.PropertyType == typeof(int?))
{
p.SetValue(myObject , 0, null);
}
}
}
}
这可以确保在使用ExecuteCommand中的参数之前,对象中的每个值都有一个值。再次,不理想,但它的确有效。
答案 7 :(得分:0)
我不喜欢使用string.format,因为(正如这个问题的当前选定答案所示),你将自己打开SQL注入。
所以我通过遍历参数来解决问题,如果参数为null,我将NULL作为字符串添加到命令文本中,如果它不为null,我添加一个将被替换的占位符(类似于字符串。使用ExecuteQuery的值(执行SQL注入检查)。
private static T ExecuteSingle<T>(string connectionString, string sprocName, params object[] sprocParameters)
where T : class
{
var commandText = sprocName;
if (sprocParameters.Length > 0)
{
// http://stackoverflow.com/questions/859985/linq-executecommand-doesnt-understand-nulls
int counter = 0;
var nulledPlaceholders = sprocParameters
.Select(x => x == null ? "NULL" : "{" + counter ++ + "}");
commandText += " " + string.Join(",", nulledPlaceholders);
sprocParameters = sprocParameters.Where(x => x != null).ToArray();
}
var connection = new SqlConnection(connectionString);
var dc = new DataContext(connection);
return dc.ExecuteQuery<T>(commandText, sprocParameters).SingleOrDefault();
}
答案 8 :(得分:0)
internal static class DataContextExtensions
{
public static int ExecuteCommandEx(this DataContext context, string command, params object[] parameters)
{
if (context == null)
throw new ArgumentNullException("context");
if (parameters != null && parameters.Length > 0)
parameters = parameters.Select(p => p ?? "NULL").ToArray();
return context.ExecuteCommand(command, parameters);
}
}
答案 9 :(得分:-1)
为什么不使用可以为空的值?
public void InsertCostumer(string? name, int? age, string? address)
{
List<object> myList = new List<object>();
myList.Add(name.GetValueOrDefault());
myList.Add(age.GetValueOrDefault());
myList.Add(address.GetValueOrDefault());
StringBuilder queryInsert = new StringBuilder();
queryInsert.Append("insert into Customers(name, address) values ({0}, {1}, {2})");
this.myDataContext.ExecuteCommand(queryInsert.ToString(), myList.ToArray());
}
答案 10 :(得分:-6)
在.NET中,null / nothing字符串不会计算为空字符串,即“”。如果你想要“”,那么必须是字符串的值,或者如果你想在SQL中表示null / nothing,如果你的.NET字符串实际上是null / nothing,你必须手动写出“NULL”。
所有execute命令都执行一个SQL查询,由您提供,作为String。它在SQL字符串方面没有做任何其他特殊的事情。
因此,要使Execute Command工作,您必须传入一个有效的SQL字符串,您必须正确地手动构造字符串。