12

Я работаю с системой, которая содержит много хранимых процедур, которые необходимо отобразить. Создание объектов для каждого из моих объектов нецелесообразно.Возврат DataTable с использованием Entity Framework ExecuteStoreQuery

Возможно ли и как вернуть 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; 
} 
+1

Связанный: Получить DataTable из регулярного запроса EF (IEnumerable): http://stackoverflow.com/questions/1253725/convert-ienumerable-to-datatable –

ответ

9

Нет, я не думаю, что будет работать - Entity Framework направлена ​​на возвращение сущности и не предназначена для возврата DataTable объектов.

Если вам нужны DataTable объектов, используйте вместо этого прямой ADO.NET.

2

Самый простой способ, чтобы вернуть DataTable с помощью EntityFramework это сделать следующее:

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

Например:

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

Что это за глобальный объект? Не знаете, откуда вы его получите. Это из Web Api 2? – Hoppe

+3

@Hoppe 'MetaTable' и' DefaultModel' (экземпляр 'MetaModel') входят в состав динамических данных ASP.NET, по существу, в виде лесов. Это не связано с платформой Entity Framework, поэтому я не думаю, что это полезный ответ. – Dai

14

Да, это возможно, но оно должно быть использовано для всего динамический результирующий набор или необработанный SQL.

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

Edit: Это лучше использовать классическую 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; 
} 
+1

Не вижу Свойство Connection для контекста? я что-то упускаю ? – user2067567

+2

Для 'DbContext', это' context.Database.Connection'. –

7

Этот метод использует строку подключения из каркаса объекта, чтобы установить соединение с 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; 
} 
4

По правилу вы не должны использовать 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'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

Очень приятно. Я изменил этот слегка открытый статический DataSet GetDataSet (этот контекст DbContext, строка sql, CommandType commandType, Dictionary parameters) – Tony

0

В моем решении на основе Entity Framework Мне нужно заменить одну из моих запросов Linq с sql - по соображениям эффективности. Также я хочу, чтобы мои результаты в DataTable из одной хранимой процедуры, чтобы я мог создать параметр значения таблицы, чтобы перейти во вторую хранимую процедуру. Итак:

  1. Я использую SQL

  2. Я не хочу DataSet

  3. Итерация IEnumerable, вероятно, не собирается резать - по соображениям эффективности

Кроме того, я использую EF6, поэтому я бы предпочел DbContext.SqlQuery по сравнению с 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; 
     } 
    } 
0

Да, это может быть легко сделано так:

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()); 
} 
Смежные вопросы