Возврат DataTable с использованием Entity Framework ExecuteStoreQuery - PullRequest
14 голосов
/ 03 января 2011

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

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

Ответы [ 8 ]

16 голосов
/ 02 июля 2012

Да, это возможно, но его следует использовать только для динамического набора результатов или необработанного 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;
}
10 голосов
/ 03 января 2011

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

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

7 голосов
/ 11 октября 2013

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

Да, это легко сделать так:

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());
}
4 голосов
/ 24 февраля 2016

По правилу вы не должны использовать 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;
    }
2 голосов
/ 12 июля 2011

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

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

Например:

MetaTable metaTable = Global.DefaultModel.GetTable("Employees");
0 голосов
/ 18 мая 2017

В моем решении на основе 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 голосов
/ 03 января 2011

Может быть, ваша хранимая процедура может вернуть сложный тип? http://blogs.msdn.com/b/somasegar/archive/2010/01/11/entity-framework-in-net-4.aspx

...