实体框架和存储过程函数使用可空参数导入

时间:2011-04-16 07:36:50

标签: entity-framework entity-framework-4 linq-to-entities entity

我注意到当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服务器的存储过程。

对此行为的一些澄清将不胜感激。

2 个答案:

答案 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。