Cómo llamar a un procedimiento almacenado en EF Core 3.0 a través de FromSqlRaw

10

Recientemente migré de EF Core 2.2 a EF Core 3.0.

Desafortunadamente, no he encontrado una manera de llamar a un procedimiento almacenado que devuelve una entidad.

En EF Core 2.0 fue posible:

var spParams = new object[] { "bla", "xx" };
var createdPath = ModelContext.Paths.FromSql("AddNodeWithPathProc  @p0, @p1", spParams).Single();

En EF Core 3.0, el método FromSQLse reemplaza por FromSqlRaw. Sin embargo, no logré llamar con éxito a un procedimiento almacenado y luego procesar el valor. Esto es útil cuando el procedimiento almacenado inserta datos en la base de datos.

Entonces, en EF Core 3.0, uso este código:

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc @p0, @p1", spParams).Single();

pero arrojará una excepción, porque el SQL generado no es válido y se ve así:

exec sp_executesql N'SELECT TOP(2) [p].[PathId], [p].[Level], [p].[NodeId], [p].[NodePath], [p].[NodePathString]
FROM (
     @sql @p0, @p1
) AS [p]',N'@p0 nvarchar(4000),@p1 nvarchar(4000), @sql nvarchar(100)',@p0=N'1a',@p1=N'', @sql=N'AddNodeWithPathProc'

Intenté algunas variaciones, pero sin éxito.

Estoy empezando a pensar que no es posible ejecutar procedimientos almacenados con ModelContext.[IQueryable].FromSqlRaw. En mi opinión, este tipo derrota una de las principales razones FromSqlRawporque, para las declaraciones de selección normales, LINQ es normalmente lo suficientemente bueno.

¿Alguien sabe cómo usar procedimientos almacenados en combinación con FromSqlRawEF Core 3.0? Cualquier ayuda es muy apreciada.

Gracias por adelantado

PD: Sé que puedes ejecutar un procedimiento almacenado con this.Database.ExecuteSqlRaw(SQL, parameters). Sin embargo, de esa manera no es posible recuperar las entidades que el procedimiento almacenado consulta.

Dan
fuente
2
Pruebe .ToList () en lugar de .Single (). .Single () está generando el contenedor "TOP (2)".
David Browne - Microsoft
mi solución temporal por el momento es la siguiente: this.ModelContext.ExecuteRawSql ("EXEC AddNodeWithPathProc @ p0, @ p1", spParams); var createdPath = ModelContext.Paths.FromSqlRaw ("SELECCIONE EL TOP 1 * DESDE dbo.Path ORDER BY PathID DESC"). Single (); Sin embargo, esta no es una solución aceptable para la producción.
Dan
sí ... ToList () funciona ... muchas gracias :-)
Dan

Respuestas:

6

Solución (gracias a David Browne, debería haberlo publicado como respuesta):

Reemplazar Single con ToList funciona :-)

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc  {0}, {1}", nodeTitle, parentPathString).ToList();
Dan
fuente
1
var result=context.yourmodelclass.FromSqlInterpolated($"StoredProcedureName {param1},{param2}").tolist();

Puede agregar múltiples parámetros si es necesario. Nota:

  • contexto => su nombre de base de datos.
  • yourmodelclass => la clase en la carpeta de modelos que crea para obtener el resultado del resultado del procedimiento almacenado.
Mohammad Irtaza
fuente
0

No estoy donde puedo probar, pero creo que lo siguiente funcionará:

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc {0}, {1}", parm1 parm2).Single();
Edney Holder
fuente
1
No, esto no funciona. Solo lo probé. El sql que no es válido :-(. Creo que tiene algo que ver con el sql que se genera. Si verifico el sql con el generador de perfiles, siempre sigue el esquema: sp_executesql 'SELECT * FROM {mySqlPassedInMethod}. No lo haría saber cómo pasar un procedimiento almacenado en este código. Entonces, el método .net detecta que la cadena sql pasada es para un procedimiento almacenado y adapta el sql generado en consecuencia o hay una forma en T-SQL que no saber (no soy un experto)
Dan
0

intenta separar SqlParameter:

SqlParameter param1 = new SqlParameter("@p0","value");
SqlParameter param2 = new SqlParameter("@p1","value");

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc @p0 @p1", param1, 
param2).Single();
ISTech
fuente
publicó una solución a su publicación eliminada a continuación.
jdweng
Simplemente lo probé y falla :-(. El error es: "System.InvalidCastException: 'SqlParameterCollection solo acepta objetos de tipo SqlParameter no nulos, no objetos SqlParameter.'". No hay ningún sql enviado al servidor sql (de acuerdo con sql profiler)
Dan
@jdweng Muchas gracias :) Esta solución la tengo cuando inicio sesión en mi software y descargo el último archivo XML actualizado con la última fecha, pero necesito todos los datos históricos de las tasas sin faltar. Así que tengo otra opción para establecer fechas y descargar el archivo de Excel con las tarifas, pero no sé cómo implementar eso. ejecutar un servicio en el servidor? tal vez los usuarios no van a usar el software durante una semana, así que me perdí toda la semana de los tipos de cambio.
ISTech
@ISTech: Consulte la siguiente página: boi.org.il/en/Markets/Pages/explainxml.aspx que puede agregar a la url una fecha. boi.org.il/currency.xml?rdate=20120101
jdweng
@ISTech: Actualicé el siguiente código para hacer un rango de fechas.
jdweng
0

Es extremadamente extraño ... justo antes de hace unos días tengo el mismo problema y sigo esta publicación. Tuve esta llamada:

 public IEnumerable<TableChange> GetTableLastChanges(string tableName, string keyColumn, out int synchronizationVersion)
    {
        var parameters = new[] {
            new SqlParameter("@table_name", SqlDbType.VarChar) { Direction = ParameterDirection.Input, Value = tableName },
            new SqlParameter("@key_column", SqlDbType.VarChar) { Direction = ParameterDirection.Input, Value = keyColumn },
            new SqlParameter("@synchronization_version", SqlDbType.BigInt) { Direction = ParameterDirection.InputOutput, Value = 0 }
        };

        var changes = this.TableChanges.FromSqlRaw("[dbo].[GetTableLastChanges] @table_name, @key_column, @synchronization_version OUTPUT", parameters).ToList();

        synchronizationVersion = Convert.ToInt32(parameters[2].Value);

        return changes;
    }

En este momento todo está bien y esta llamada funciona como se esperaba. Por lo tanto, debo admitir que no hay ningún problema con los conjuntos de datos y el retorno de parámetros para EF en Core 3.

juriko
fuente
0

Echa un vistazo aquí:

https://github.com/DarioN1/SPToCore

Este es un andamio para el procedimiento almacenado, puede ayudarlo a trabajar con sp.

No es una biblioteca de una tercera parte, generó un código puro de C # para incluir en su proyecto que extiende dbContext actual para proporcionar métodos de procedimientos almacenados, asignación de parámetros y resultados clasificados.

DarioN1
fuente