Entity Framework EF4.1 - хранимая процедура "не найдена в контейнере" - PullRequest
7 голосов
/ 11 декабря 2011

У меня есть SP в моей базе данных. Для EF4.1, используя DbContext API .

После импорта функции из модели данных ссылки на хранимую процедуру прекрасно работают в моей среде разработки. Но при публикации на сервере происходит сбой с сообщением типа: FunctionImport 'SqlSearch' не найден в контейнере 'TallyJ2Entities'. Все остальные данные работают нормально.

Похоже, что при производстве некоторые аспекты конфигурации EF4 забываются.

Базы данных идентичны, и оба сервера являются SQL 2008 (локальный - Express SP1 10.50.2500, хост - Express RTM 10.50.1600).

Я даже указал редактору EDMX непосредственно на производственную базу данных и обновил его. Результат отлично работал при разработке, но на сервере не сработал.

Другие подобные вопросы здесь не помогают. У кого-то еще есть похожая проблема введите описание ссылки здесь .

Есть предложения?

Обновление: Я обнаружил, что проблема исчезает при развертывании хоста в режиме отладки!

Внутри моего производного класса 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, оказывается, что сервер (в режиме Release) НЕ нашел его, а в процессе разработки он обнаружен.

Ответы [ 3 ]

19 голосов
/ 18 мая 2012

При использовании EF 4.1 и выше измените «ObjectParameter» на «SqlParameter» и «ExecuteFunction» на «ExecuteStoreQuery» в файле Context.cs.

Метод «ExecuteStoreQuery» также ожидает, что вы добавите имена параметров перед сохраненным процессом. Найдите фрагмент ниже:

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

Если вы используете шаблон для генерации вашего кода, вам может быть полезен также приведенный ниже фрагмент кода. То есть Я изменил стандартный генератор "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);
        }
    }
5 голосов
/ 09 июля 2014

Мы обнаружили, что это вызвано неправильной строкой соединения.

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.

0 голосов
/ 02 марта 2015

Я не думаю, что строка подключения является проблемой. В моем случае я не могу вызвать процедуру хранилища, но я могу записать данные в мою БД.это означает, что наша связь правильная.

...