12

Estoy trabajando con un sistema que tiene muchos procedimientos almacenados que deben mostrarse. Crear entidades para cada uno de mis objetos no es práctico.Devolviendo una DataTable utilizando Entity Framework ExecuteStoreQuery

¿Es posible y cómo devolvería un DataTable usando ExecuteStoreQuery?

public ObjectResult<DataTable> MethodName(string fileSetName) { 
using (var dataContext = new DataContext(_connectionString)) 
{ 
var returnDataTable = ((IObjectContextAdapter)dataContext).ObjectContext.ExecuteStoreQuery<DataTable>("SP_NAME","SP_PARAM"); 
return returnDataTable; 
} 
+1

Relacionado: Obtenga una DataTable de una consulta EF normal (un IEnumerable): http://stackoverflow.com/questions/1253725/convert-ienumerable-to-datatable –

Respuesta

9

No, no creo que se va a trabajar - Marco de la entidad se orienta a regresar entidades y no tiene la intención de volver DataTable objetos.

Si necesita objetos DataTable, use ADO.NET directo en su lugar.

2

La forma más fácil de devolver un DataTable utilizando el ADO.NET Entity Framework es hacer lo siguiente:

MetaTable metaTable = Global.DefaultModel.GetTable("Your EntitySetName"); 

Por ejemplo:

MetaTable metaTable = Global.DefaultModel.GetTable("Employees"); 
+2

¿Qué es este objeto global? No estoy seguro de dónde lo estás obteniendo. ¿Es de Web Api 2? – Hoppe

+3

@Hoppe 'MetaTable' y' DefaultModel' (una instancia de 'MetaModel') son parte de ASP.NET DynamicData, esencialmente un framework de andamios. No está relacionado con Entity Framework, así que no creo que sea una respuesta útil en absoluto. – Dai

14

Sí, es posible, pero debe ser utilizado por sólo conjunto de resultados dinámicos o SQL sin formato.

public DataTable ExecuteStoreQuery(string commandText, params Object[] parameters) 
{ 
    DataTable retVal = new DataTable(); 
    retVal = context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault(); 
    return retVal; 
} 

Editar: Es mejor utilizar ADO.NET clásico para obtener el modelo de datos en lugar de utilizar Marco de la entidad porque la mayoría probablemente no puede utilizar DataTable incluso si se puede ejecutar el método: context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault();

ADO.NET ejemplo:

public DataSet GetResultReport(int questionId) 
{ 
    DataSet retVal = new DataSet(); 
    EntityConnection entityConn = (EntityConnection)context.Connection; 
    SqlConnection sqlConn = (SqlConnection)entityConn.StoreConnection; 
    SqlCommand cmdReport = new SqlCommand([YourSpName], sqlConn); 
    SqlDataAdapter daReport = new SqlDataAdapter(cmdReport); 
    using (cmdReport) 
    { 
     SqlParameter questionIdPrm = new SqlParameter("QuestionId", questionId); 
     cmdReport.CommandType = CommandType.StoredProcedure; 
     cmdReport.Parameters.Add(questionIdPrm); 
     daReport.Fill(retVal); 
    } 
    return retVal; 
} 
+1

¿No veo la propiedad Connection para Context? Me estoy perdiendo de algo ? – user2067567

+2

Para 'DbContext', es' context.Database.Connection'. –

7

este método utiliza la cadena de conexión desde el marco de la entidad para establecer una conexión ADO.NET, a una base de datos MySQL en este ejemplo.

using MySql.Data.MySqlClient; 

public DataSet GetReportSummary(int RecordID) 
{ 
    var context = new catalogEntities(); 

    DataSet ds = new DataSet(); 
    using (MySqlConnection connection = new MySqlConnection(context.Database.Connection.ConnectionString)) 
    { 
     using (MySqlCommand cmd = new MySqlCommand("ReportSummary", connection)) 
     { 
      MySqlDataAdapter adapter = new MySqlDataAdapter(cmd); 
      adapter.SelectCommand.CommandType = CommandType.StoredProcedure; 
      adapter.SelectCommand.Parameters.Add(new MySqlParameter("@ID", RecordID)); 
      adapter.Fill(ds); 
     } 
    } 
    return ds; 
} 
4

Por regla general, no debe usar un DataSet dentro de una aplicación EF. Pero, si realmente necesita (por ejemplo, para alimentar un informe), que la solución debe trabajar (que es código EF 6):

DataSet GetDataSet(string sql, CommandType commandType, Dictionary<string, Object> parameters) 
    { 
     // creates resulting dataset 
     var result = new DataSet(); 

     // creates a data access context (DbContext descendant) 
     using (var context = new MyDbContext()) 
     { 
      // creates a Command 
      var cmd = context.Database.Connection.CreateCommand(); 
      cmd.CommandType = commandType; 
      cmd.CommandText = sql; 

      // adds all parameters 
      foreach (var pr in parameters) 
      { 
       var p = cmd.CreateParameter(); 
       p.ParameterName = pr.Key; 
       p.Value = pr.Value; 
       cmd.Parameters.Add(p); 
      } 

      try 
      { 
       // executes 
       context.Database.Connection.Open(); 
       var reader = cmd.ExecuteReader(); 

       // loop through all resultsets (considering that it's possible to have more than one) 
       do 
       { 
        // loads the DataTable (schema will be fetch automatically) 
        var tb = new DataTable(); 
        tb.Load(reader); 
        result.Tables.Add(tb); 

       } while (!reader.IsClosed); 
      } 
      finally 
      { 
       // closes the connection 
       context.Database.Connection.Close(); 
      } 
     } 

     // returns the DataSet 
     return result; 
    } 
+0

Muy agradable. Modifiqué este conjunto de datos GetDataSet DataSet ligeramente público (este DbContext context, string sql, CommandType commandType, Dictionary parámetros) – Tony

0

En mi solución basada Entity Framework tengo que sustituir uno de mis consultas LINQ con sql, por razones de eficiencia. También quiero mis resultados en un DataTable de un procedimiento almacenado para poder crear un parámetro de valor de tabla para pasar a un segundo procedimiento almacenado. Por lo tanto:

  1. estoy usando SQL

  2. no quiero una iteración DataSet

  3. un IEnumerable probablemente no se va a cortar - por razones de eficiencia

Además, estoy usando EF6, por lo que preferiría DbContext.SqlQuery sobre ObjectContext.ExecuteStoreQuery como lo solicitó el póster original.

Sin embargo, he encontrado que esto simplemente no funcionó:

_Context.Database.SqlQuery<DataTable>(sql, parameters).FirstOrDefault();

Ésta es mi solución. Devuelve un DataTable que se obtiene utilizando un ADO.NET SqlDataReader, que creo que es más rápido que un SqlDataAdapter en datos de solo lectura. No responde estrictamente a la cuestión, ya que utiliza ADO.Net, pero muestra cómo hacerlo después de conseguir un asimiento de la conexión desde el DbContext

protected DataTable GetDataTable(string sql, params object[] parameters) 
    { 
     //didn't work - table had no columns or rows 
     //return Context.Database.SqlQuery<DataTable>(sql, parameters).FirstOrDefault(); 

     DataTable result = new DataTable(); 
     SqlConnection conn = Context.Database.Connection as SqlConnection; 
     if(conn == null) 
     { 
      throw new InvalidCastException("SqlConnection is invalid for this database"); 
     } 
     using (SqlCommand cmd = new SqlCommand(sql, conn)) 
     { 
      cmd.Parameters.AddRange(parameters); 
      conn.Open(); 
      using (SqlDataReader reader = cmd.ExecuteReader()) 
      { 
       result.Load(reader); 
      } 
      return result; 
     } 
    } 
0

Sí, se puede hacer fácilmente así:

var table = new DataTable(); 
using (var ctx = new SomeContext()) 
{ 
    var cmd = ctx.Database.Connection.CreateCommand(); 
    cmd.CommandText = "Select Col1, Col2 from SomeTable"; 

    cmd.Connection.Open(); 
    table.Load(cmd.ExecuteReader()); 
} 
Cuestiones relacionadas