it-swarm.com.de

Rückgabe einer DataTable mit Entity Framework ExecuteStoreQuery

Ich arbeite mit einem System, das viele gespeicherte Prozeduren enthält, die angezeigt werden müssen. Das Erstellen von Objekten für jedes meiner Objekte ist nicht praktikabel. 

Ist es möglich und wie würde ich eine DataTable mit ExecuteStoreQuery zurückgeben?

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;
}
13
detroitpro

Nein, ich glaube nicht, dass das funktionieren wird - Entity Framework ist auf die Rückgabe von Entitäten ausgerichtet und soll keine DataTable-Objekte zurückgeben.

Wenn Sie DataTable-Objekte benötigen, verwenden Sie stattdessen direktes ADO.NET.

10
marc_s

Ja, es ist möglich, aber es sollte nur für dynamische Ergebnismengen oder Roh-SQL verwendet werden.

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

Bearbeiten: Es ist besser, klassisches ADO.NET zu verwenden, um das Datenmodell abzurufen, anstatt Entity Framework zu verwenden, da Sie DataTable höchstwahrscheinlich nicht verwenden können, selbst wenn Sie die Methode ausführen können: context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault();

ADO.NET-Beispiel:

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;
}
15
chuck

Diese Methode verwendet die Verbindungszeichenfolge aus dem Entitätsframework zum Herstellen einer ADO.NET-Verbindung zu einer MySQL-Datenbank in diesem Beispiel.

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;
}
7
jim31415

Ja, das geht einfach so:

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
CodingYoshi

In der Regel sollten Sie kein DataSet in einer EF-Anwendung verwenden. Wenn Sie jedoch wirklich einen Bericht erstellen müssen (z. B. einen Bericht), sollte diese Lösung funktionieren (EF 6-Code):

    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;
    }
4
Daniel Brilho

Die einfachste Möglichkeit, eine DataTable mithilfe des EntityFrameworks zurückzugeben, besteht in der folgenden Vorgehensweise:

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

Zum Beispiel:

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

Vielleicht könnte Ihre gespeicherte Prozedur einen komplexen Typ zurückgeben? http://blogs.msdn.com/b/somasegar/archive/2010/01/11/entity-framework-in-net-4.aspx

0
RobbanP

In meiner auf Entity Framework basierenden Lösung muss ich aus Effizienzgründen eine meiner Linq-Abfragen durch sql ersetzen. Außerdem möchte ich meine Ergebnisse in einer gespeicherten Prozedur in einem DataTable speichern, damit ich einen Tabellenwertparameter erstellen kann, der an eine zweite gespeicherte Prozedur übergeben wird. Damit:

  1. Ich benutze SQL

  2. Ich möchte kein DataSet

  3. Das Iterieren eines IEnumerable wird es wahrscheinlich aus Effizienzgründen nicht beenden

Außerdem verwende ich EF6, daher würde ich _DbContext.SqlQueryObjectContext.ExecuteStoreQuery_ als angefordertes Originalposter vorziehen.

Ich stellte jedoch fest, dass dies einfach nicht funktionierte:

_Context.Database.SqlQuery<DataTable>(sql, parameters).FirstOrDefault();

Das ist meine Lösung. Es gibt ein DataTable zurück, das mit einem ADO.NET SqlDataReader abgerufen wird - was meiner Meinung nach bei schreibgeschützten Daten schneller ist als ein SqlDataAdapter. Die Frage wird nicht streng beantwortet, da ADO.Net verwendet wird. Es wird jedoch gezeigt, wie dies getan wird, nachdem die Verbindung von DbContext angehalten wurde.

_    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
Colin