Возврат объекта 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;
}

8 ответов


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

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


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

этот метод использует строку подключения из Entity framework для установки 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;
}

по правилу вы не должны использовать набор данных внутри приложения 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;
    }

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

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

например:

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

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

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());
}

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


в моем решении на основе 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;
        }
    }