In dit geval moet u niet bellen:
var query = ctx.Database.SqlQuery<CmdRegisterAssetDto>(sql, projectNameParam, countryCodeParam, locationParam, assetRegisteredParam);
Maar bel in plaats daarvan:
var result = ctx.Database.ExecuteSqlCommand(sql, projectNameParam, countryCodeParam, locationParam, assetRegisteredParam);
Merk op dat het enige effectieve verschil is dat SqlQuery<CmdRegisterAssetDto>
werd vervangen door ExecuteSqlCommand
. Dit betekent ook dat de DTO overbodig is. Anders ziet uw code eruit alsof het zou moeten werken. Hier is je originele code in zijn geheel met de wijzigingen die ik noemde:
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;
}
Om mijn theorie te bewijzen, reproduceerde ik het nulgedrag dat je ervaart en maakte toen die ene verandering. Het hing een beetje (waarschijnlijk om EF in de versnelling te laten komen), maar werd daarna elke keer snel uitgevoerd. In elk geval vond ik een waarde die wacht in de out-parameter.
Als iemand daarbuiten in de problemen komt, is er een lange-hand-variant die de scriptdetails voor je regelt:
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;
}
Bij nader inzien zou je technisch gezien kunnen kiezen voor je oorspronkelijke oplossing als je de query onmiddellijk daarna aanroept (d.w.z. query.FirstOrDefault()
). De geretourneerde waarde van de query zou altijd null zijn, maar uw out-parameter zou op zijn minst worden ingevuld. Dit komt omdat EF-query's uitgestelde uitvoering gebruiken.