sql >> Base de Datos >  >> RDS >> Oracle

¿Llamar al procedimiento almacenado de Oracle usando Entity Framework con parámetro de salida?

En este caso, no debería llamar:

var query = ctx.Database.SqlQuery<CmdRegisterAssetDto>(sql, projectNameParam, countryCodeParam, locationParam, assetRegisteredParam);

Pero en lugar de eso llama:

var result = ctx.Database.ExecuteSqlCommand(sql, projectNameParam, countryCodeParam, locationParam, assetRegisteredParam);

Tenga en cuenta que la única diferencia efectiva es que SqlQuery<CmdRegisterAssetDto> fue reemplazado por ExecuteSqlCommand . Esto también significa que el DTO es innecesario. De lo contrario, su código parece que debería funcionar. Aquí está su código original en su totalidad con los cambios que mencioné:

string projectName = "EXCO";
string location = "ANYWHERE";
string countryCode = "XX";

using (var ctx = new RAContext())
{
    var projectNameParam = new OracleParameter("inProjectName", OracleDbType.Varchar2, projectName, ParameterDirection.Input);
    var countryCodeParam = new OracleParameter("inCountryCode", OracleDbType.Varchar2, countryCode, ParameterDirection.Input);
    var locationParam = new OracleParameter("inLocation", OracleDbType.Varchar2, location, ParameterDirection.Input);
    var assetRegisteredParam = new OracleParameter("OutAssetRegistered", OracleDbType.Varchar2, ParameterDirection.Output);

    var sql = "BEGIN RA.RA_RegisterAsset(:inProjectName, :inCountryCode, :inLocation, :OutAssetRegistered); END;";
    var result = ctx.Database.ExecuteSqlCommand(sql, projectNameParam, countryCodeParam, locationParam, assetRegisteredParam);

    assetRegistered = (string)assetRegisteredParam.Value;
}

Para probar mi teoría, reproduje el comportamiento nulo que estás experimentando y luego hice ese cambio. Se colgó un poco (probablemente para permitir que EF se pusiera en marcha), pero luego se ejecutó rápidamente cada vez a partir de entonces. En cada caso, encontré un valor esperando en el parámetro de salida.

Si alguien por ahí tiene problemas, hay una variación manual que se encarga de los detalles de las secuencias de comandos por usted:

string projectName = "EXCO";
string location = "ANYWHERE";
string countryCode = "XX";

using (var ctx = new RAContext())
using (var cmd = ctx.Database.Connection.CreateCommand())
{
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = "RA.RA_REGISTERASSET";

    var projectNameParam = new OracleParameter("inProjectName", OracleDbType.Varchar2, projectName, ParameterDirection.Input);
    var countryCodeParam = new OracleParameter("inCountryCode", OracleDbType.Varchar2, countryCode, ParameterDirection.Input);
    var locationParam = new OracleParameter("inLocation", OracleDbType.Varchar2, location, ParameterDirection.Input);
    var assetRegisteredParam = new OracleParameter("OutAssetRegistered", OracleDbType.Varchar2, ParameterDirection.Output);
    cmd.Parameters.AddRange(new[] { projectNameParam, countryCodeParam, locationParam, assetRegisteredParam });

    cmd.Connection.Open();
    var result = cmd.ExecuteNonQuery();
    cmd.Connection.Close();

    assetRegistered = (string)assetRegisteredParam.Value;
}

Como idea de último momento, técnicamente podría optar por su solución original si invocara la consulta inmediatamente después (es decir, query.FirstOrDefault() ). El valor de retorno de la consulta siempre sería nulo, pero su parámetro de salida al menos se completaría. Esto se debe a que las consultas de EF utilizan la ejecución diferida.