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

3
我注意到当Entity Framework为存储过程(函数导入)生成方法时,它会测试参数是否为null,并做出如下决策:
if (contactID.HasValue)
{
  contactIDParameter = new ObjectParameter("contactID", contactID);
}  
else
{
  contactIDParameter = new ObjectParameter("contactID", typeof(global::System.Int32));
}

当参数为null时,通过将参数的类型作为参数传递,我不明白它试图做什么?在这种情况下,存储过程/函数如何执行?

我用SQL Profiler进行了测试,并注意到当我故意将参数设置为null(通过调用类似context.MyProcedure(null)之类的东西),null只是作为参数传递给SQL服务器的存储过程。

希望对此行为进行一些澄清。

2个回答

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;
}

可以看到,即使是空值也必须表示为ObjectParameter,因为你不能简单地传递null - 否则会抛出异常。 PopulateFunctionEntityCommandParameters 使用有关类型的信息为调用存储过程创建正确的DbParameter。该参数的值为DBNull.Value

因此,您不必处理它。这只是基础设施。


1
当您查看类ObjectParameter构造函数的代码时
public ObjectParameter (string name, object value)
public ObjectParameter (string name, Type type)

你可以看到,ObjectParameter有3个重要的私有字段:
_name(参数名称,不为空且不可变),_type(参数的CLR类型,不为空且不可变),_value(参数的值,可更改且可空)
当使用第一个构造函数时,这些字段都被初始化。使用第二个构造函数时,_value字段被留空为null。
在EF的ExecuteFunction中,会使用一个名为CreateEntityCommandForFunctionImport的私有方法,该方法调用另一个更深层次的私有方法PopulateFunctionImportEntityCommandParameters,该方法附加实体参数。
在PopulateFunctionImportEntityCommandParameters内部,EntityParameter的一个实例(表示EntityCommand中的参数)将映射到ObjectParameter的名称和值属性。
这条指令解释了所有内容:
entityParameter.Value = objectParameter.Value ?? DBNull.Value;

如果没有指定参数值,我们将DBNull传递给EF。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接