实体框架 EF4.1 - 存储过程“在容器中找不到”

Posted

技术标签:

【中文标题】实体框架 EF4.1 - 存储过程“在容器中找不到”【英文标题】:Entity Framework EF4.1 - stored procedure "could not be found in the container" 【发布时间】:2011-12-11 05:27:07 【问题描述】:

我的数据库中有一个 SP。对于 EF4.1,使用 DbContext API。

从数据模型导入函数后,对存储过程的引用在我的开发环境中工作正常。但是当发布到服务器时,它会失败并显示如下消息:在容器“TallyJ2Entities”中找不到 FunctionImport 'SqlSearch'。所有其他数据访问工作正常。

似乎在生产中,EF4配置的某些方面被遗忘了。

数据库完全相同,两台服务器都是 SQL 2008(本地是 Express SP1 10.50.2500,主机是 Express RTM 10.50.1600)。

我什至将 EDMX 编辑器直接指向生产数据库,并进行了更新。结果在开发中运行良好,但在服务器上以相同的方式失败。

其他类似问题here 无济于事。其他人似乎也有类似的问题enter link description here。

有什么建议吗?

更新:我发现当我在调试模式下部署主机时问题消失了!

在我的 DbContext 派生类中,我输入了以下代码:

((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace
var findFunction = metadataWorkspace.GetItems(DataSpace.SSpace)
            .SelectMany(gi => gi.MetadataProperties)
            .Where(m=> Equals(m.Value, "SqlSearch"))
            .Select(m => "Found 0".FilledWith(m.Value))
            .FirstOrDefault();

当我记录findFunction 结果时,发现服务器(在发布模式下)没有找到它,而在开发中,它找到了。

【问题讨论】:

似乎有很多关于这个的问题:***.com/a/3501174/2942***.com/questions/4892926/… 谢谢。但这些其他想法都对我不起作用。 【参考方案1】:

如果使用 EF 4.1 及更高版本,请将 Context.cs 文件中的“ObjectParameter”更改为“SqlParameter”,将“ExecuteFunction”更改为“ExecuteStoreQuery”。

“ExecuteStoreQuery”方法还希望您在存储过程的前面添加参数名称。在下面找到一个 sn-p:

var param1Parameter = param1 != null ?
new SqlParameter("param1", param1) :
new SqlParameter("param1", typeof(string));

var param2Parameter = param2 != null ?
new SqlParameter("param2", param2) :
new SqlParameter("param2", typeof(int));

return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<sp_TestSproc_Result>("sp_TestSproc @param1, @param2", param1Parameter, param2Parameter);

如果使用模板生成代码,您可能会发现下面的 sn-p 也很有用。 IE。我已经修改了标准的“Fluent TT”生成器以适应 EF 4.3:

    void WriteFunctionImport(EdmFunction edmFunction, bool includeMergeOption)
    
        var parameters = FunctionImportParameter.Create(edmFunction.Parameters, Code, EFTools);
        var paramList = String.Join(", ", parameters.Select(p => p.FunctionParameterType + " " + p.FunctionParameterName).ToArray());
        var returnType = edmFunction.ReturnParameter == null ? null : EFTools.GetElementType(edmFunction.ReturnParameter.TypeUsage);
        var processedReturn = returnType == null ? "int" : "ObjectResult<" + MultiSchemaEscape(returnType) + ">";

        if (includeMergeOption)
        
            paramList = Code.StringAfter(paramList, ", ") + "MergeOption mergeOption";
        
    #>

        <#=AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction))#> <#=processedReturn#> <#=Code.Escape(edmFunction)#>(<#=paramList#>)
        
    <#+
            if(returnType != null && (returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType ||
                                      returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType))
            
    #>
            ((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(<#=MultiSchemaEscape(returnType)#>).Assembly);

    <#+
            

            foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable))
            
                var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null";
                var notNullInit = "new SqlParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")";
                var nullInit = "new SqlParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + parameter.RawClrTypeName + "))";
    #>
            var <#=parameter.LocalVariableName#> = <#=isNotNull#> ?
                <#=notNullInit#> :
                <#=nullInit#>;

    <#+
            

            var genericArg = returnType == null ? "" : "<" + MultiSchemaEscape(returnType) + ">";
            var callParams = Code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()));
            var spParams = Code.StringBefore("@", String.Join(", @", parameters.Select(p => p.EsqlParameterName).ToArray()));

            if (includeMergeOption)
            
                callParams = ", mergeOption" + callParams;
            
    #>
            return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<#=genericArg#>("<#=edmFunction.Name#> <#=spParams#>"
                        <#=callParams#>);
        
    <#+
        if(!includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
        
            WriteFunctionImport(edmFunction, true);
        
    

【讨论】:

谢谢...我会在接下来的一两周内尝试一下。希望能够退出调试模式! 完美,谢谢!不知道我自己要花多长时间才能找到这个! 我正在尝试做类似的事情,但我没有 sp,我有 TVF。我收到一条错误消息:“函数不是 sp,它是 TVF”。您知道如何解决这个问题吗?【参考方案2】:

我们发现这是由错误的connectionString引起的。

EF 需要一个如下所示的连接字符串:

<connectionStrings>
  <add name="MyModel_Entities" connectionString="metadata=res://*/Models.MyModel.csdl|res://*/Models.MyModel.ssdl|res://*/Models.MyModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=192.168.1.200;initial catalog=MyDb_Live;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>

MyModel 这应该与您的 .edmx 模型文件的名称相对应。

如果您从其他地方复制了一个连接字符串,它可能如下所示:

<add name="MyModel_Entities" connectionString="Data Source=.;Initial Catalog=MyDb_Live;Integrated Security=SSPI;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />

特别注意连接字符串末尾的 providerName 的不同。

NB 我们使用的是 EF 6.1,但我相信这也适用于早期版本。 如果您修复了我们发现的连接字符串,您可以继续使用 T4 模板生成的代码。您无需将 ObjectParameter 切换为 SqlParameter 并将 ExecuteFunction 切换为 ExecuteStoreQuery。

【讨论】:

我同意...连接字符串格式对 EF 至关重要。感谢您强调这一点。 我在我的项目中添加了 2 个 EDMX,我只是复制粘贴了连接字符串,这最终成为了我的解决方案。因为我有错误的“MyModel”,所以它在另一个容器中寻找存储过程。谢谢【参考方案3】:

我不认为连接字符串是问题。在我的情况下,我无法调用存储过程,但我能够将数据写入我的数据库。这意味着我们的连接是正确的。

【讨论】:

以上是关于实体框架 EF4.1 - 存储过程“在容器中找不到”的主要内容,如果未能解决你的问题,请参考以下文章

具有实体框架 4.1 和父/子关系的存储库模式

动态存储过程和 EF4.1

在容器中找不到 Docker“/usr/bin/php”

存储过程参数名称和实体框架

实体框架存储过程表值参数

在实体框架中使用存储过程