Ответ 1
Нет, я не думаю, что это сработает. Entity Framework ориентирован на возвращение объектов и не предназначен для возврата объектов DataTable
.
Если вам нужны объекты DataTable
, используйте вместо этого прямой ADO.NET.
Я работаю с системой, в которой есть много хранимых процедур, которые необходимо отобразить. Создание объектов для каждого из моих объектов нецелесообразно.
Возможно ли это и как вернуть DataTable
с помощью 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;
}
Нет, я не думаю, что это сработает. Entity Framework ориентирован на возвращение объектов и не предназначен для возврата объектов DataTable
.
Если вам нужны объекты DataTable
, используйте вместо этого прямой ADO.NET.
Да, это возможно, но оно должно использоваться только для динамического набора результатов или необработанного SQL.
public DataTable ExecuteStoreQuery(string commandText, params Object[] parameters)
{
DataTable retVal = new DataTable();
retVal = context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault();
return retVal;
}
Изменить: лучше использовать классический ADO.NET для получения модели данных, а не для использования Entity Framework, потому что, скорее всего, вы не можете использовать DataTable
, даже если вы можете запустить метод: context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault();
Пример ADO.NET:
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;
}
Этот метод использует строку соединения из фреймворка сущности для установления соединения ADO.NET с базой данных MySQL в этом примере.
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;
}
По правилу вы не должны использовать DataSet внутри приложения EF. Но если вам действительно нужно (например, подать отчет), это решение должно работать (это код 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 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;
}
Самый простой способ вернуть DataTable с помощью EntityFramework - сделать следующее:
MetaTable metaTable = Global.DefaultModel.GetTable("Your EntitySetName");
Например:
MetaTable metaTable = Global.DefaultModel.GetTable("Employees");
Возможно, ваша хранимая процедура может вернуть сложный тип? http://blogs.msdn.com/b/somasegar/archive/2010/01/11/entity-framework-in-net-4.aspx
В моем решении на основе Entity Framework мне нужно заменить один из моих запросов Linq на sql - по соображениям эффективности.
Также я хочу, чтобы мои результаты были в DataTable
из одной хранимой процедуры, чтобы я мог создать параметр значения таблицы, чтобы перейти во вторую хранимую процедуру. Итак:
Я использую sql
Я не хочу DataSet
Итерация IEnumerable
, вероятно, не собирается сокращать ее - по соображениям эффективности
Кроме того, я использую EF6, поэтому я бы предпочел DbContext.SqlQuery
over ObjectContext.ExecuteStoreQuery
по запросу оригинального плаката.
Однако я обнаружил, что это просто не сработало:
_Context.Database.SqlQuery<DataTable>(sql, parameters).FirstOrDefault();
Это мое решение. Он возвращает DataTable
, который извлекается с использованием ADO.NET SqlDataReader
, который, я считаю, быстрее, чем SqlDataAdapter
для данных только для чтения. Он не строго отвечает на вопрос, потому что он использует ADO.Net, но он показывает, как это сделать после получения связи из 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;
}
}
Да, это можно сделать следующим образом:
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());
}