所以我的问题是这个。当使用Data Context ExecuteQuery(字符串查询,params object []参数)(here)时,我无法以任何形式或形式传递null。启动此操作的参数是SQL nvarchar参数,需要允许空值。
我在stackoverflow上读到这个article,其中“使用DBNull.Value”标记为答案 - 所以我尝试了,没有任何东西(如果它不起作用,那么想知道答案是怎么回事? ?!)。
以下是我尝试运行的示例代码(注意,这只是为了测试这个概念):
var db = new Test1DataContext(Properties.Settings.Default.TestConnectionString);
var query = "EXEC UpInsertTest4 {0}, {1}";
// Works fine
var list1 = new List<object> { 1, "1" };
db.ExecuteQuery<UpInsertTest4Result>(query, list1.ToArray());
// Doesn't work
var list2 = new List<object> { 1, DBNull.Value };
db.ExecuteQuery<UpInsertTest4Result>(query, list2.ToArray());
以下是我收到的各种错误:
null : A query parameter cannot be of type 'System.Object'.
default(string) : A query parameter cannot be of type 'System.Object'.
DBNull.Value : Unexpected type code: DBNull (which give this as a stack trrace)
at System.Data.Linq.SqlClient.SqlTypeSystem.Sql2005Provider.From(Type type, Nullable`1 size)
at System.Data.Linq.SqlClient.SqlTypeSystem.Sql2008Provider.From(Type type, Nullable`1 size)
at System.Data.Linq.SqlClient.SqlTypeSystem.ProviderBase.From(Type type)
at System.Data.Linq.SqlClient.SqlTypeSystem.ProviderBase.From(Object o)
at System.Data.Linq.SqlClient.SqlFactory.ValueFromObject(Object value, Type clrType, Boolean isClientSpecified, Expression sourceExpression)
at System.Data.Linq.SqlClient.QueryConverter.VisitConstant(ConstantExpression cons)
at System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
at System.Data.Linq.SqlClient.QueryConverter.VisitExpression(Expression exp)
at System.Data.Linq.SqlClient.QueryConverter.VisitUserQuery(String query, Expression[] arguments, Type resultType)
at System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
at System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
at System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataContext.ExecuteMethodCall(Object instance, MethodInfo methodInfo, Object[] parameters)
at System.Data.Linq.DataContext.ExecuteQuery[TResult](String query, Object[] parameters)
at ConsoleApplication1.Program.Main(String[] args) in E:\TestBed\Testbed\ConsoleApplication1\Program.cs:line 36
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
从我读过的内容来看,我可能正在为此而战!这是我最后的尝试!
非常感谢,
克里斯。
答案 0 :(得分:5)
你可以这样做:
db.ExecuteQuery<UpInsertTest4Result>(string.Format(query,1,"null"));
<强>更新强>
是的,我已经测试了解决方案。它不会包含@p1=N'null'
。因为我直接使用sql作为字符串。所以概念很多。
存储程序:
CREATE PROCEDURE testas
@test1 INT,
@test2 INT
AS
SELECT 1 test
用于测试输出的类:
public class testout
{
public int test { get; set; }
}
使用db上下文查询Linq:
var query="exec testas {0}, {1}";
db.ExecuteQuery<testout>(string.Format(query,"0","null"));
如果你查看linqpad,sql输出是这样的:
exec testas 0, null
字符串格式正在改变字符串。这与写这个相同:
db.ExecuteQuery<testout>("exec testas 0, null")
答案 1 :(得分:1)
我遇到了同样的问题,我在这个论坛上找到了解决方案:https://social.msdn.microsoft.com/Forums/en-US/20b318bc-32cf-466b-972e-6cd37e625cd6/a-query-parameter-cannot-be-of-the-type-systemobject?forum=linqprojectgeneral
基本上,目标是创建一个扩展方法,该方法将分析参数并将所有空参数直接替换为请求 示例:&#34; EXEC MyStoredProcedure {0},{1},{2},{3}&#34;第二个参数值为null将变为&#34; EXEC MyStoredProcedure {0},NULL,{1},{2}&#34;第二个参数将从数组参数中删除。
以下是方法:
internal static IEnumerable<TResult> ExecuteQueryNullSafe<TResult>(this System.Data.Linq.DataContext context, string command, params object[] parameters)
{
var list = new List<object>();
var listVals = new List<bool>();
for (int x = 0; x < parameters.Count(); x++)
{
if (parameters[x] == null || parameters[x] is System.DBNull)
{
command = command.Replace("{" + x + "}", "NULL");
listVals.Add(false);
}
else
{
list.Add(parameters[x]);
listVals.Add(true);
}
}
int nextId = 0;
for (int i = 0; i < listVals.Count; i++)
{
var isUsed = listVals[i];
if (!isUsed)
continue;
if (nextId != i)
command = command.Replace("{" + i.ToString() + "}", "{" + nextId.ToString() + "}");
nextId++;
}
return context.ExecuteQuery<TResult>(command, list.ToArray());
}
答案 2 :(得分:0)
试试这个克里斯:
void Main()
{
var db = new Test1DataContext(Properties.Settings.Default.TestConnectionString);
db.UpInsertTest4Result(1,"1");
db.UpInsertTest4Result(1,null);
db.UpInsertTest4Result(null,"1");
db.UpInsertTest4Result(null,null);
}
public class Test1DataContext : DataContext
{
public Test1DataContext(string connStr) : base(connStr) { }
[Function(Name = "UpInsertTest4")]
public IEnumerable<UpInsertTest4Result> UpInsertTest4Result(
[Parameter(Name = "par1", DbType = "Int")] int? par1,
[Parameter(Name = "par2", DbType = "VarChar")] string par2)
{
var result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), par1,par2);
return (IEnumerable<UpInsertTest4Result>)result.ReturnValue;
}
}