La devolución de un DataTable utilizando Entity Framework ExecuteStoreQuery
-
14-10-2019 - |
Pregunta
Estoy trabajando con un sistema que tiene muchos procedimientos almacenados que se deben mostrar. La creación de entidades para cada uno de mis objetos no es práctico.
¿Es posible y cómo tendría que devolver una 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;
}
Solución
No, no creo que se va a trabajar. - Marco de la entidad está orientada a devolver entidades y no está destinado a objetos de retorno DataTable
Si necesita DataTable
objetos, utilizar ADO.NET recta en su lugar.
Otros consejos
Sí, es posible, pero se debe utilizar para conjunto de resultados simplemente dinámico o SQL prima.
public DataTable ExecuteStoreQuery(string commandText, params Object[] parameters)
{
DataTable retVal = new DataTable();
retVal = context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault();
return retVal;
}
Edit: 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 se 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;
}
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;
}
Sí, se puede hacer fácilmente de esta manera:
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());
}
Por la regla, no debe utilizar un conjunto de datos dentro de una aplicación EF. Pero, si realmente necesita (por ejemplo, para alimentar un informe), que la solución debe trabajar (que de EF 6 Código):
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;
}
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");
Tal vez el procedimiento almacenado puede devolver un tipo de complejo? http: // blogs .msdn.com / b / Somasegar / archivo / 2010/01/11 / entidad-marco-en-red-4.aspx
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 que pudiera crear un parámetro de valor de la tabla a pasar a un segundo procedimiento almacenado. Por lo tanto:
-
Estoy usando SQL
-
No quiero un
DataSet
-
Iterar una
IEnumerable
probablemente no se va a cortar - por razones de eficiencia
Además, yo estoy usando EF6, por lo que yo preferiría DbContext.SqlQuery
sobre ObjectContext.ExecuteStoreQuery
como el cartel original solicitado.
Sin embargo, he encontrado que esto simplemente no funcionó:
_Context.Database.SqlQuery<DataTable>(sql, parameters).FirstOrDefault();
Esta es mi solución. Devuelve un DataTable
se descargará y utilizando un SqlDataReader
ADO.NET - que creo que es más rápido que un SqlDataAdapter
en los datos de sólo 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;
}
}