¿Cómo ejecutar procedimientos almacenados en Entity Framework Core?

Estoy utilizando EF7 (entity framework de la estructura) en una aplicación asp.net core. ¿Puede indicarme la forma correcta de ejecutar los procedimientos almacenados? El método anterior con ObjectParameters y ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction no funciona.

El soporte para el procedimiento almacenado en EF7 se resuelve ahora, esto también admite el mapeo de múltiples conjuntos de resultados.

Verifique aquí los detalles del arreglo

Y puede llamarlo así: var userType = dbContext.Set().FromSql("dbo.SomeSproc @Id = {0}, @Name = {1}", 45, "Ada");

El soporte de procedimientos almacenados todavía no está implementado (a partir de 7.0.0-beta3) en EF7. Puede seguir el progreso de esta función usando el número 245 .

Por ahora, puedes hacerlo a la antigua usanza con ADO.NET.

 var connection = (SqlConnection)context.Database.AsSqlServer().Connection.DbConnection; var command = connection.CreateCommand(); command.CommandType = CommandType.StoredProcedure; command.CommandText = "MySproc"; command.Parameters.AddWithValue("@MyParameter", 42); command.ExecuteNonQuery(); 

Para ejecutar los procedimientos almacenados, use el método FromSql que ejecuta consultas RAW SQL

p.ej

 var products= context.Products .FromSql("EXECUTE dbo.GetProducts") .ToList(); 

Para usar con parámetros

 var productCategory= "Electronics"; var product = context.Products .FromSql("EXECUTE dbo.GetProductByCategory {0}", productCategory) .ToList(); 

o

 var productCategory= new SqlParameter("productCategory", "Electronics"); var product = context.Product .FromSql("EXECUTE dbo.GetProductByName @productCategory", productCategory) .ToList(); 

Existen ciertas limitaciones para ejecutar consultas RAW SQL o procedimientos almacenados. No puede usarlo para INSERT / UPDATE / DELETE. si desea ejecutar INSERTAR, ACTUALIZAR, ELIMINAR consultas, utilice ExecuteSqlCommand

 var categoryName = "Electronics"; dataContext.Database           .ExecuteSqlCommand("dbo.InsertCategory @p0", categoryName); 

"(SqlConnection)context" – Este tipo de conversión ya no funciona. Puede hacer: "SqlConnection context;

".AsSqlServer()" – No existe.

"command.ExecuteNonQuery();" – No devuelve resultados. reader=command.ExecuteReader() funciona.

Con dt.load (lector) … entonces tiene que cambiar el marco de 5,0 y volver a 4.51, ya que 5.0 no admite datatables / datasets, aún. Nota: Este es VS2015 RC.

Actualmente, EF 7 o EF Core no son compatibles con el antiguo método de importar procedimientos almacenados en el diseñador y llamarlos directamente. Puede echar un vistazo a la hoja de ruta para ver qué se va a admitir en el futuro: hoja de ruta central de EF .

Así que, por ahora, es mejor usar SqlConnection para llamar a procedimientos almacenados o cualquier consulta sin formato, ya que no necesita la EF completa para este trabajo. Aquí hay dos ejemplos:

Llame al procedimiento almacenado que devuelve un valor único. Cadena en este caso.

 CREATE PROCEDURE [dbo].[Test] @UserName nvarchar(50) AS BEGIN SELECT 'Name is: '+@UserName; END 

Llamar al procedimiento almacenado que devuelve una lista.

 CREATE PROCEDURE [dbo].[TestList] AS BEGIN SELECT [UserName], [Id] FROM [dbo].[AspNetUsers] END 

Para llamar a estos procedimientos almacenados, es mejor crear una clase estática que contenga todas estas funciones, por ejemplo, la llamé clase DataAccess, de la siguiente manera:

 public static class DataAccess { private static string connectionString = ""; //Your connection string public static string Test(String userName) { using (SqlConnection conn = new SqlConnection(connectionString)) { conn.Open(); // 1. create a command object identifying the stored procedure SqlCommand cmd = new SqlCommand("dbo.Test", conn); // 2. set the command object so it knows to execute a stored procedure cmd.CommandType = CommandType.StoredProcedure; // 3. add parameter to command, which will be passed to the stored procedure cmd.Parameters.Add(new SqlParameter("@UserName", userName)); // execute the command using (var rdr = cmd.ExecuteReader()) { if (rdr.Read()) { return rdr[0].ToString(); } else { return null; } } } } public static IList TestList() { using (SqlConnection conn = new SqlConnection(connectionString)) { conn.Open(); // 1. create a command object identifying the stored procedure SqlCommand cmd = new SqlCommand("dbo.TestList", conn); // 2. set the command object so it knows to execute a stored procedure cmd.CommandType = CommandType.StoredProcedure; // execute the command using (var rdr = cmd.ExecuteReader()) { IList result = new List(); //3. Loop through rows while (rdr.Read()) { //Get each column result.Add(new Users() { UserName = (string)rdr.GetString(0), Id = rdr.GetString(1) }); } return result; } } } } 

Y la clase de los usuarios es así:

 public class Users { public string UserName { set; get; } public string Id { set; get; } } 

Por cierto, no tiene que preocuparse por el rendimiento de abrir y cerrar una conexión para cada solicitud de sql, ya que asp.net se ocupa de gestionar esto por usted. Y espero que esto haya sido útil.

Tuve muchos problemas con ExecuteSqlCommand y ExecuteSqlCommandAsync , los parámetros IN fueron fáciles, pero los parámetros OUT fueron muy difíciles.

Tuve que volver a usar DbCommand como tal –

 DbCommand cmd = _context.Database.GetDbConnection().CreateCommand(); cmd.CommandText = "dbo.sp_DoSomething"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new SqlParameter("@firstName", SqlDbType.VarChar) { Value = "Steve" }); cmd.Parameters.Add(new SqlParameter("@lastName", SqlDbType.VarChar) { Value = "Smith" }); cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.BigInt) { Direction = ParameterDirection.Output }); 

Escribí más sobre esto en esta publicación .

El soporte para el procedimiento almacenado en EF Core es similar a las versiones anteriores del Código EF primero.

Necesita crear su clase DbContext insertando la clase DbContext de EF. Los procedimientos almacenados se están ejecutando con DbContext.

El primer paso es escribir un método que cree un DbCommand desde el DbContext.

 public static DbCommand LoadStoredProc( this DbContext context, string storedProcName) { var cmd = context.Database.GetDbConnection().CreateCommand(); cmd.CommandText = storedProcName; cmd.CommandType = System.Data.CommandType.StoredProcedure; return cmd; } 

Para pasar parámetros al procedimiento almacenado, use el siguiente método.

 public static DbCommand WithSqlParam( this DbCommand cmd, string paramName, object paramValue) { if (string.IsNullOrEmpty(cmd.CommandText)) throw new InvalidOperationException( "Call LoadStoredProc before using this method"); var param = cmd.CreateParameter(); param.ParameterName = paramName; param.Value = paramValue; cmd.Parameters.Add(param); return cmd; } 

Finalmente, para mapear el resultado en una lista de objetos personalizados, use el método MapToList.

 private static List MapToList(this DbDataReader dr) { var objList = new List(); var props = typeof(T).GetRuntimeProperties(); var colMapping = dr.GetColumnSchema() .Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower())) .ToDictionary(key => key.ColumnName.ToLower()); if (dr.HasRows) { while (dr.Read()) { T obj = Activator.CreateInstance(); foreach (var prop in props) { var val = dr.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value); prop.SetValue(obj, val == DBNull.Value ? null : val); } objList.Add(obj); } } return objList; } 

Ahora estamos listos para ejecutar el procedimiento almacenado con el método ExecuteStoredProc y lo mapeamos a la Lista cuyo tipo ha pasado como T.

 public static async Task> ExecuteStoredProc(this DbCommand command) { using (command) { if (command.Connection.State == System.Data.ConnectionState.Closed) command.Connection.Open(); try { using (var reader = await command.ExecuteReaderAsync()) { return reader.MapToList(); } } catch(Exception e) { throw (e); } finally { command.Connection.Close(); } } } 

Por ejemplo, para ejecutar un procedimiento almacenado llamado “StoredProcedureName” con dos parámetros llamados “firstparamname” y “secondparamname”, esta es la implementación.

 List myTypeList = new List(); using(var context = new MyDbContext()) { myTypeList = context.LoadStoredProc("StoredProcedureName") .WithSqlParam("firstparamname", firstParamValue) .WithSqlParam("secondparamname", secondParamValue). .ExecureStoredProc(); } 

Usando el conector MySQL y Entity Framework Core 2.0

Mi problema era que recibía una excepción como fx. Ex.Message = “La columna requerida ‘cuerpo’ no estaba presente en los resultados de una operación ‘FromSql'”. Por lo tanto, para obtener filas a través de un procedimiento almacenado de esta manera, debe devolver todas las columnas para ese tipo de entidad con el que está asociado el DBSet, incluso si no necesita acceder a todo para su solicitud actual.

 var result = _context.DBSetName.FromSql($"call storedProcedureName()").ToList(); 

O con parámetros

 var result = _context.DBSetName.FromSql($"call storedProcedureName({optionalParam1})").ToList(); 

Si está ejecutando un procedimiento almacenado desde Informix utilizando EntityFrameworkCore, debe incluir el comando EXECUTE PROCEDURE

 var spresult = _informixContext.procdata.FromSql("EXECUTE PROCEDURE dummyproc ({0},{1},{2})", parameters: new[] { p0, p1,p2 }).ToList();