2

我注意到,当实体框架生成一个存储过程(函数导入)的方法,它测试,看看参数为空,并使得这样的决定:实体框架和存储过程,函数导入可空参数

if (contactID.HasValue) 
{ 
    contactIDParameter = new ObjectParameter("contactID", contactID); 
} 
else 
{ 
    contactIDParameter = new ObjectParameter("contactID", typeof(global::System.Int32)); 
} 

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

我用SQL Profiler自己做了一个测试,并注意到当我故意传递null作为参数时(通过调用类似context.MyProcedure(null)的方法),仅仅将null作为参数传递给SQL服务器的存储过程。

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

回答

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,因为你不能简单地通过空 - 它会抛出异常。 PopulateFunctionEntityCommandParameters使用有关该类型的信息来创建用于调用存储过程的正确的DbParameter。该参数的值是DBNull.Value

所以你不必处理它。这只是基础设施。

+0

非常感谢您对水晶般清晰的解释! – user683202 2011-04-18 00:22:43

1

当你看这个类的代码ObjectParameter构造

public ObjectParameter (string name, object value) 
public ObjectParameter (string name, Type type) 

你可以看到ObjectParameter有3个重要的私人领域:

_name(参数的名称,而不是零和不可改变的),_type( CLR类型的参数,非空且不可更改),_value(参数的值,可以更改且为空)

当第一个结构uctor被使用,这些字段全部被初始化。对于第二个构造函数,_value字段留为null

在EF的ExecuteFunction中,使用私有方法CreateEntityCommandForFunctionImport,其调用另一个甚至更深的专用方法PopulateFunctionImportEntityCommandParameters,该方法附加实体参数。

PopulateFunctionImportEntityCommandParameters里面,表示EntityCommand中的参数的EntityParameter的实例将被映射到名称和值的属性ObjectParameter

该指令可以解释这一切:

entityParameter.Value = objectParameter.Value ?? DBNull.Value; 

我们通过DBNull到EF如果没有值被指定为一个参数。