Usage of stored functions in entity framework

gdoron is supporting Monica picture gdoron is supporting Monica · Oct 9, 2012 · Viewed 9.1k times · Source

I have an old Oracle DB which I'm trying to use within EntityFramework 4.1 application.
I've read about the big limitation that oracle has with EF- you can't call Oracle stored Function with EF unless you create a wrapping Procedure.

I got thousands of stored functions in my DB, is there any other way to solve it?
Like using raw Context.SqlQuery()?

So far I couldn't find a solution for it...


Oracle docs:

Oracle developers can leverage PL/SQL stored procedures, with limitations, within the entity framework via Entity Framework Function Imports (used to call the procedures explicitly) and stored procedure mappings (which are automatically called for entity Insert, Update, and Delete operations).

Only Oracle stored procedures can be called by Entity Framework, not stored functions. (Oracle stored functions can be used if they are wrapped inside of a stored procedure that uses an OUT parameter for the stored function return value.)

Answer

Devart picture Devart · Oct 10, 2012

If you are working with Entity Framework 4.1 Code First, you can try using the Database.SqlQuery Method . For example, for this function

CREATE OR REPLACE FUNCTION USERNAME_CTX.FUNCTION1 (param number)
 RETURN number
AS
BEGIN
 return param + 1;
END;

you can use this code:

using (var ctx = new Model()) {
   var result =  ctx.Database.SqlQuery<int>("select username_ctx.FUNCTION1(:p0) from dual",1).FirstOrDefault();

}

EDITED:

Please note this solution for dotConnect for Oracle (maybe it will be useful for implementing a similar solution for ODP.NET)

For this function:

CREATE OR REPLACE FUNCTION USERNAME_CTX.FUNCTION2 (param number, int_param out number, str_param out varchar2)
  RETURN number
AS
BEGIN
   int_param := param + 2;
   str_param := 'value';
   return param + 1;
END;

You can use the following code:

   using (var ctx = new Model()) {
       var firstParam = new Devart.Data.Oracle.OracleParameter("p0", OracleDbType.Number, 1, ParameterDirection.Input);
       var secondParam = new Devart.Data.Oracle.OracleParameter("p1", OracleDbType.Number, ParameterDirection.Output);
       var thirdParam = new Devart.Data.Oracle.OracleParameter("p2", OracleDbType.VarChar, ParameterDirection.Output);
       var cursorParam = new Devart.Data.Oracle.OracleParameter("cursor_param", OracleDbType.Cursor, ParameterDirection.Output);

       var result = ctx.Database.SqlQuery<int>(
        @"declare
             res number;  
        begin
             res := username_ctx.FUNCTION2(:p0, :p1, :p2);
             open :cursor_param for select res from dual;
        end;",  firstParam, secondParam, thirdParam, cursorParam).FirstOrDefault();

       Console.WriteLine("Return value: {0}; int_param: {1}; str_param: '{2}'", result, secondParam.Value, thirdParam.Value);
      }

EDITED 2

or use this code:

     using (var ctx = new Model()) {
       var firstParam = new Devart.Data.Oracle.OracleParameter("p0", OracleDbType.Number, 1, ParameterDirection.Input);
       var secondParam = new Devart.Data.Oracle.OracleParameter("p1", OracleDbType.Number, ParameterDirection.Output);
       var thirdParam = new Devart.Data.Oracle.OracleParameter("p2", OracleDbType.VarChar, ParameterDirection.Output);
       var resultParam = new Devart.Data.Oracle.OracleParameter("res", OracleDbType.Number, 1, ParameterDirection.Output);
       ctx.Database.ExecuteSqlCommand(@"begin  :res := username_ctx.FUNCTION2(:p0, :p1, :p2);  end;", firstParam, secondParam, thirdParam, resultParam);
       Console.WriteLine("Return value: {0}; int_param: {1}; str_param: '{2}'", resultParam.Value, secondParam.Value, thirdParam.Value);
 }