使用带有输出参数的Entity Framework调用Oracle存储过程?

时间:2016-08-19 11:17:47

标签: c# oracle entity-framework entity-framework-6 oracle-manageddataaccess

我有一个简单的Oracle存储过程,它传入三个参数,并有一个输出参数:

CREATE OR REPLACE PROCEDURE RA.RA_REGISTERASSET
(
    INPROJECTNAME IN VARCHAR2
    ,INCOUNTRYCODE IN VARCHAR2
    ,INLOCATION IN VARCHAR2
    ,OUTASSETREGISTERED OUT VARCHAR2
)
AS
BEGIN
  SELECT 
      INPROJECTNAME || ', ' || INLOCATION || ', ' || INCOUNTRYCODE
  INTO
      OUTASSETREGISTERED
  FROM
      DUAL;     
END RA_REGISTERASSET;

我正在尝试使用Entity Framework 6.1来获取OutAssetRegistered值,但是,在调用SqlQuery后我得到一个null,没有例外:

public class CmdRegisterAssetDto
{
        public string inProjectName { get; set; }
        public string inCountryCode { get; set; }
        public string inLocation { get; set; }
        public string OutAssetRegistered { get; set; }
}

// --------------------------------------------- ---------------

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 query = ctx.Database.SqlQuery<CmdRegisterAssetDto>(sql, projectNameParam, countryCodeParam, locationParam, assetRegisteredParam
    );

    assetRegistered = (string)assetRegisteredParam.Value;
}

我一直在争取让这个工作无济于事,检查过不同的博客,所有其他的crud操作都工作,有人可以协助并指导我在哪里出错吗?

1 个答案:

答案 0 :(得分:1)

在这种情况下,你不应该打电话:

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

而是致电:

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

请注意,唯一有效的区别是SqlQuery<CmdRegisterAssetDto>已替换为ExecuteSqlCommand。这也意味着DTO是不必要的。否则,您的代码看起来应该可以工作。以下是我提到的更改的原始代码:

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

为了证明我的理论,我重现了你正在经历的空行为,然后做出了一个改变。它挂了一点(可能让EF开始进入),但之后每次都快速执行。在每种情况下,我都在out参数中找到了一个值。

如果有任何人遇到麻烦,那么有一个简单的变体可以为您处理脚本细节:

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

作为事后的想法,如果您在之后立即调用查询(即query.FirstOrDefault()),您在技术上可以使用原始解决方案。查询的返回值始终为null,但out参数至少会填充。这是因为EF查询使用延迟执行。