具有可为空参数的实体框架和存储过程函数导入

发布于 2024-11-01 21:33:17 字数 494 浏览 1 评论 0原文

我注意到,当实体框架为存储过程(函数导入)生成方法时,它会测试参数是否为空,并做出如下决定:

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 Server 的存储过程。

如果对此行为进行一些澄清,我们将不胜感激。

I noticed that when Entity Framework generates a method for a stored procedure (function import), it tests to see if the parameter is null, and makes a decision like this:

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

I don't understand what its trying to do by passing the Type of the parameter as a parameter when the parameter is null? Exactly how does the stored procedure/function get executed in this case?

I did a test myself with SQL Profiler, and noticed that when I intentionally pass null as a parameter (by calling something like context.MyProcedure(null) ), null is simply passed as the parameter to the SQL server's stored procedure.

Some clarifications on this behavior would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

风柔一江水 2024-11-08 21:33:17

我对这个问题很感兴趣,所以做了一些调查。

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

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

I was interested in this question so I made some investigation.

ObjectParameter has two overloads - one for passing value and one for passing the type. The second is used if you pass null as the parameter value because EF internally need this. The reason is that function import must be called with ObjectParameters, not with plain parameters you are passing to the wrapping method.

Internally EF calls:

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

As you can see even null value must be represented as ObjectParameter because you can't simply pass null - it will throw exception. The PopulateFunctionEntityCommandParameters uses information about the type to create correct DbParameter for calling the stored procedure. The value of that parameter is DBNull.Value.

So you don't have to deal with it. It is just infrastructure.

酷到爆炸 2024-11-08 21:33:17

当您查看类 ObjectParameter 构造函数的代码时,

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

您可以看到 ObjectParameter 有 3 个重要的私有字段:

_name (参数名称,不为 null并且不可变),_type(参数的CLR类型,不为空且不可变),_value(参数的值,可以更改且可为空)

当第一个构造函数是使用时,这些字段都已初始化。对于第二个构造函数,_value 字段保留为 null

在 EF 的 ExecuteFunction 中,使用私有方法 CreateEntityCommandForFunctionImport 来调用另一个更深层次的私有方法 PopulateFunctionImportEntityCommandParameters 来附加实体参数。

PopulateFunctionImportEntityCommandParameters 内,代表 EntityCommand 中参数的 EntityParameter 实例将映射到 ObjectParameter 的名称和值属性代码>.

该指令解释了这一切:

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

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

When you watch the code of the class ObjectParameter constructors

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

You can see that ObjectParameter has 3 important private fields:

_name (name of parameter, not null and immutable), _type (CLR type of the parameter, not null and immutable), _value (value of the parameter, can be changed and nullable)

When the first constructor is used, these fields are all initialized. With the second constructor, the _value field is left to be null.

In the ExecuteFunction of EF, a private method CreateEntityCommandForFunctionImport is used which calls another even deeper private method PopulateFunctionImportEntityCommandParameters which attaches the entity parameters.

Inside PopulateFunctionImportEntityCommandParameters, an instance of EntityParameter which represents a parameter in EntityCommand will be mapped to the name and value's properties of ObjectParameter.

This instruction explains it all:

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

We pass the DBNull to EF if no value was specified as a parameter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文