Linq ExecuteCommand不理解空值

时间:2009-05-13 19:37:54

标签: c# linq-to-sql null

使用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,则不会发生错误。我知道我的例子中的设计有点差,我只是创建了一个简化的例子来关注这个问题。有什么建议吗?

11 个答案:

答案 0 :(得分:19)

这是一个已知错误,Microsoft不打算修复它......

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=305114&wa=wsignin1.0

解决方法是:

  1. 直接进入ADO.NET并执行SQL命令
  2. 格式化您自己执行的字符串并使用空对象数组调用ExecuteCommand(新对象[0])
  3. 第二个不是一个好主意,因为它打开了你的SQL注入攻击,但它是一个快速黑客。

答案 1 :(得分:1)

Kevin is right

他在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字符串,您必须正确地手动构造字符串。

相关问题