2012-06-05 25 views
8

Necesito ejecutar una consulta personalizada que se guardará en algún lugar de la base de datos y necesito que regrese en una tabla de datos, o conjunto de datos y lo vincule a una vista de cuadrícula que tendrá columnas autogeneradas en verdadero.ejecutar sql personalizado con entity framework?

Toda mi capa de acceso a datos funciona perfecto con marco de la entidad, pero por alguna situación especial que deba hacer esto y me pregunto si debería combinar con ado.net marco de la entidad, o si EF puede hacerlo de alguna manera

Respuesta

8

Si su objetivo es devolver estructuras ADO.NET (DataTable o DataSet), simplemente use ADO.NET clásico. Lo encontrará más fácil que tratar de vincular datos a un conjunto de Entidades y luego rellenar un DataTable o un DataSet usted mismo.

Sin embargo, si está realmente interesado en ejecutar una consulta personalizada a través de EntityFramework, eche un vistazo a ExecuteQuery. Le permite ejecutar una consulta SQL y correlaciona el resultado con las entidades de su modelo. Entonces sería un ejercicio de su parte tomar el resultado de IEnumerable y asignarlo a un DataTable o DataSet. De ahí mi respuesta original de "simplemente hazlo con buenos métodos anticuados ADO.NET".

16

Para Entity Framework 5 uso

context.Database.SqlQuery


Y Para Entity Framework 4 utilizar el siguiente código

context.ExecuteStoreQuery


public string BuyerSequenceNumberMax(int buyerId) 
    { 
     string sequenceMaxQuery = "SELECT TOP(1) btitosal.BuyerSequenceNumber FROM BuyerTakenItemToSale btitosal " + 
            "WHERE btitosal.BuyerID = " + buyerId + 
            "ORDER BY CONVERT(INT,SUBSTRING(btitosal.BuyerSequenceNumber,7, LEN(btitosal.BuyerSequenceNumber))) DESC"; 

     var sequenceQueryResult = context.Database.SqlQuery<string>(sequenceMaxQuery).FirstOrDefault(); 

     string buyerSequenceNumber = string.Empty; 

     if (sequenceQueryResult != null) 
     { 
      buyerSequenceNumber = sequenceQueryResult.ToString(); 
     } 

     return buyerSequenceNumber; 
    } 

Para devolver una lista utilizar el siguiente código

public List<PanelSerialList> PanelSerialByLocationAndStock(string locationCode, byte storeLocation, string itemCategory, string itemCapacity, byte agreementType, string packageCode) 
{ 
     string panelSerialByLocationAndStockQuery = "SELECT isws.ItemSerialNo, im.ItemModel " + 
     "FROM Inv_ItemMaster im " + 
     "INNER JOIN " + 
     "Inv_ItemStockWithSerialNoByLocation isws " + 
     " ON im.ItemCode = isws.ItemCode " + 
     "  WHERE isws.LocationCode = '" + locationCode + "' AND " + 
     " isws.StoreLocation = " + storeLocation + " AND " + 
     " isws.IsAvailableInStore = 1 AND " + 
     " im.ItemCapacity = '" + itemCapacity + "' AND " + 
     " isws.ItemSerialNo NOT IN (" + 
     "   Select sp.PanelSerialNo From Special_SpecialPackagePriceForResale sp " + 
     "   Where sp.PackageCode = '" + packageCode + "')"; 



    context.Database.SqlQuery<PanelSerialList>(panelSerialByLocationAndStockQuery).ToList(); 


} 
+7

Si no está seguro de que ha higienizado todas las entradas, el uso de SQL parámetros para evitar ataques de inyección SQL. –

9

Aquí hay otra dimensión y el enfoque más fácil. Obtener conexión de SQL utilizando el Contexto de Entity Framework:

var connection = (System.Data.SqlClient.SqlConnection) _db.Database.Connection; 

if (connection != null && connection.State == ConnectionState.Closed) 
{ 
    connection.Open(); 
} 

var dt = new DataTable(); 

using (var com = new System.Data.SqlClient.SqlDataAdapter("Select * from Table", connection)) 
{ 
    com.Fill(dt); 
} 

Y podemos usar DataAdapter o cualquier otro método clásico para ejecutar consultas utilizando la conexión EF.

Esto será muy útil cuando hacemos algo dinámicamente y cuando no podemos mapear a una entidad. Podemos obtener cosas en una DataTable por ejemplo.

La sintaxis anterior es para EF 5.0.

2

Uso EF6 y un día necesitaba forma de ejecutar una cadena SQL dinámica y obtener DataTable. En primer lugar, simplemente eché DbContext.Database.Connection a SqlConnection e hice un trabajo completo. Funcionó para las pruebas, pero la aplicación se rompió, porque Glimpse, que usamos, inyecta la auto-implementación de DbConnection con el tipo Glimpse.Ado.AlternateType.GlimpseDbConnection. Necesito un enfoque que funcione independientemente de lo que es DbConnection.Por último termino con el código siguiente:

public class SqlDataProvider : ISqlDataProvider 
{ 
    private readonly DbContext _context; 

    public SqlDataProvider(DbContext context) 
    { 
     _context = context; 
    } 

    public DataTable GetDataTable(string sqlQuery) 
    { 
     try 
     { 
      DbProviderFactory factory = DbProviderFactories.GetFactory(_context.Database.Connection); 

      using (var cmd = factory.CreateCommand()) 
      { 
       cmd.CommandText = sqlQuery; 
       cmd.CommandType = CommandType.Text; 
       cmd.Connection = _context.Database.Connection; 
       using (var adapter = factory.CreateDataAdapter()) 
       { 
        adapter.SelectCommand = cmd; 

        var tb = new DataTable(); 
        adapter.Fill(tb); 
        return tb; 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new SqlExecutionException(string.Format("Error occurred during SQL query execution {0}", sqlQuery), ex); 
     } 
    } 

y esto funciona para cualquier caso: En los ensayos en DbContext.Database.Connection es SqlConnection y para Glimpse.Ado.AlternateType.GlimpseDbConnection

Cuestiones relacionadas