我注意到当Entity Framework为存储过程(函数导入)生成一个方法时,它会测试参数是否为null,并做出如下决定:
if (contactID.HasValue)
{
contactIDParameter = new ObjectParameter("contactID", contactID);
}
else
{
contactIDParameter = new ObjectParameter("contactID", typeof(global::System.Int32));
}
当参数为null时,通过将参数的类型作为参数传递,我不明白它试图做什么?在这种情况下,存储过程/函数究竟是如何执行的?
我自己使用SQL事件探查器进行了测试,并注意到当我故意将null作为参数传递时(通过调用context.MyProcedure(null)之类的东西),null只是作为参数传递给SQL服务器的存储过程。
对此行为的一些澄清将不胜感激。
答案 0 :(得分:2)
我对这个问题感兴趣所以我做了一些调查。
ObjectParameter
有两个重载 - 一个用于传递值,另一个用于传递类型。如果您传递null作为参数值,则使用第二个,因为EF内部需要此值。原因是必须使用ObjectParameters调用函数导入,而不是使用传递给包装方法的普通参数。
内部EF电话:
private EntityCommand CreateEntityCommandForFunctionImport(string functionName, out EdmFunction functionImport, params ObjectParameter[] parameters)
{
...
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i] == null)
{
throw EntityUtil.InvalidOperation(Strings.ObjectContext_ExecuteFunctionCalledWithNullParameter(i));
}
}
...
this.PopulateFunctionEntityCommandParameters(parameters, functionImport, command);
return command;
}
正如你所看到的,即使null值必须表示为ObjectParameter,因为你不能简单地传递null - 它会抛出异常。 PopulateFunctionEntityCommandParameters
使用有关类型的信息来创建用于调用存储过程的正确DbParameter
。该参数的值为DBNull.Value
。
所以你不必处理它。它只是基础设施。
答案 1 :(得分:1)
当您观看类ObjectParameter
构造函数
public ObjectParameter (string name, object value)
public ObjectParameter (string name, Type type)
您可以看到ObjectParameter
有3个重要的私有字段:
_name
(参数名称,非null且不可变),_type
(参数的CLR类型,非null且不可变),_value
(参数的值,可以是改变和可空)
使用第一个构造函数时,这些字段都已初始化。使用第二个构造函数,_value
字段将保留为null
。
在EF的ExecuteFunction
中,使用了一个私有方法CreateEntityCommandForFunctionImport
,它调用另一个更深层次的私有方法PopulateFunctionImportEntityCommandParameters
来附加实体参数。
在PopulateFunctionImportEntityCommandParameters
内,代表EntityParameter
中参数的EntityCommand
实例将映射到ObjectParameter
的名称和值属性。
本说明解释了所有内容:
entityParameter.Value = objectParameter.Value ?? DBNull.Value;
如果没有将值指定为参数,我们会将DBNull
传递给EF。