2012-06-05 15 views
8

Potrzebuję wykonać niestandardową kwerendę, która zostanie zapisana gdzieś w bazie danych i potrzebuję go, aby zwrócić w datatable lub zestaw danych i powiązać go do gridview, który automatycznie generuje kolumny true.wykonać niestandardowy sql ze strukturą encji?

Całe warstwa dostępu do danych działa idealnie z Entity Framework, ale z jakiegoś konkretnego scenariusza muszę to zrobić i zastanawiam się, czy należy łączyć z ADO.NET Entity Framework, czy EF może to zrobić jakoś

Odpowiedz

8

Jeśli twoim celem jest zwrócenie struktur ADO.NET (DataTable lub DataSet), użyj klasycznego ADO.NET. Przekonasz się, że jest to łatwiejsze niż próba powiązania danych z zestawem jednostek, a następnie samodzielne zapełnianie DataTable lub DataSet.

Jeśli jednak naprawdę chcesz uruchomić niestandardowe zapytanie za pośrednictwem EntityFramework, spójrz na numer ExecuteQuery. Pozwala na wykonanie zapytania SQL i odwzorowuje wynik z powrotem na elementy w modelu. Byłoby wtedy ćwiczeniem z twojej strony, aby przyjąć wynik IEnumerable i zmapować go na DataTable lub DataSet. Stąd moja oryginalna odpowiedź "po prostu zrób to z dobrymi metodami ADO.NET".

16

Dla Entity Framework 5 użycie

context.Database.SqlQuery


a dla Entity Framework 4 użyć następującego kodu

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

Dla zwróci listę użyć następującego kodu

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

Jeśli nie jesteś pewien, że oczyszczone wszystkich wejść, użycie SQL parametry zapobiegające atakom SQL injection. –

9

Oto kolejny wymiar i łatwiejsze podejście. Uzyskaj połączenia SQL przy użyciu kontekstu 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); 
} 

I możemy użyć DataAdapter lub jakąkolwiek inną metodę klasyczną do wykonywania zapytań za pomocą połączenia EF.

Będzie to bardzo przydatne, gdy robimy coś dynamicznie i kiedy nie możemy odwzorować na Entity. Możemy np. Pobrać dane z DataTable.

Powyższa składnia dotyczy EF 5.0.

2

Używam EF6 i pewnego dnia potrzebowałem sposobu na wykonanie dynamicznego ciągu SQL i uzyskanie DataTable. Najpierw po prostu rzuciłem DbContext.Database.Connection do SqlConnection i wykonałem całą pracę. To działało na testy, ale aplikacja została złamana, ponieważ Glimpse, którego używamy, wstrzykuje sobie implementację DbConnection z typem Glimpse.Ado.AlternateType.GlimpseDbConnection. Potrzebuję podejścia, które działa niezależnie od tego, czym jest DbConnection.W końcu skończyć z następującego kodu:

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

A to działa na każdym wypadku: do badań gdzie DbContext.Database.Connection jest SqlConnection i Glimpse.Ado.AlternateType.GlimpseDbConnection

Powiązane problemy