2016-08-03 29 views
6

Stworzyliśmy WebAPI do wysyłania zapytań do bazy danych Oracle. Kwerenda zwraca wyniki, które są ogromne, więc czasami wyrzuca OutOfMemoryException.Wzywając ogromne dane zwracane przez Web API

Zalecono użycie koncepcji Paging. Nie rozumiem, w jaki sposób aplikacja kliencka będzie wiedziała, ile razy musi zostać wywołany interfejs API, aby uzyskać cały zestaw wyników. Muszę również utworzyć oddzielną klasę dla stronicowania lub mogę operować nią w moim kontrolerze API.

Czy ktoś może mi pomóc, ponieważ jest to moje pierwsze internetowe API. Nie możemy create procedury przechowywane na to, ponieważ mamy tylko do odczytu na bazie

public HttpResponseMessage Getdetails([FromUri] string[] id) 
{ 
    string connStr = ConfigurationManager.ConnectionStrings["ProDataConnection"].ConnectionString; 
    using (OracleConnection dbconn = new OracleConnection(connStr)) 
    { 
     var inconditions = id.Distinct().ToArray(); 
     var srtcon = string.Join(",", inconditions); 
     DataSet userDataset = new DataSet(); 
     var strQuery = @"SELECT * from STCD_PRIO_CATEGORY where STPR_STUDY.STD_REF IN(" + srtcon + ")"; 
     using (OracleCommand selectCommand = new OracleCommand(strQuery, dbconn)) 
     { 
       using (OracleDataAdapter adapter = new OracleDataAdapter(selectCommand)) 
      { 
       DataTable selectResults = new DataTable(); 
       adapter.Fill(selectResults); 
       var returnObject = new { data = selectResults }; 
       var response = Request.CreateResponse(HttpStatusCode.OK, returnObject, MediaTypeHeaderValue.Parse("application/json")); 
       ContentDispositionHeaderValue contentDisposition = null; 

       if (ContentDispositionHeaderValue.TryParse("inline; filename=ProvantisStudyData.json", out contentDisposition)) 
       { 
        response.Content.Headers.ContentDisposition = contentDisposition; 
       } 

       return response; 
      } 
     } 
    } 
} 
+3

Twój kod ma problem sql-wtrysku. Przeczytaj, jak używać parametrów poleceń. – rene

Odpowiedz

6

Ogólną ideą stronicowania poprzez API jest to, że klient przejdzie do strony „” danych, które chcą i „ilość” rekordów, które chcą.

Stamtąd można zbudować swoje coś zapytanie do skutku

Select all records, but skip ((Page - 1) * amount) of records and take (amount) of records.

Jeśli używasz LINQ to SQL istnieją Take() i Skip() metody, które pomogą zrobić to o wiele łatwiej napisać po stronie kodowej. Jeśli nie używasz LINQ do SQL, musisz znaleźć coś konkretnego dla Oracle.

Ostatnia uwaga, ponieważ dobry interfejs API został zaprojektowany jako "bezpaństwowy", będzie wymagał od klienta zachowania strony, na której są obsługiwani podczas obsługi zapytań na poprzedniej/następnej stronie. Zazwyczaj zmienne strony i kwoty są przechowywane w JavaScript lub nawet coś tak prostego, jak ukryte zmienne i można ich użyć do obliczenia liczby stron, które są dostępne, i tym podobne. Oto podstawowa próbka wywołania WebAPI, które wykonuję, stronicowania. . Być może trzeba zmodyfikować go trochę do obsługi coraz wszelkie rekordy i potencjalnie coś Oracle specyficzne jeśli LINQ to SQL/EF nie obsługuje go:

public IActionResult GetProducts(int? page, int? count) 
     { 
      var takePage = page ?? 1; 
      var takeCount = count ?? DefaultPageRecordCount; 

      var calls = context.Products 
          .Skip((takePage - 1) * takeCount) 
          .Take(takeCount) 
          .ToList(); 

      return Json(calls); 
     } 
+0

Dziękuję Dillie-O, ale co, jeśli klient chce cały zestaw rekordów na raz. Czy to jest możliwe. – user4912134

+0

@ user4912134 - Jeśli użytkownik chce mieć wszystkie rekordy jednocześnie, możesz umieścić coś w swoim interfejsie API, aby ignorować opcje take/skip, jeśli podały wartość strony równą -99 lub po prostu wartość null, ale zazwyczaj po napotkaniu wartości pustej mieć domyślny zastępczy. –

+0

Dziękuję Dillie-O, więc będę musiała zmienić mój wybór. Czy są jakieś proste próbki, które można odnieść do – user4912134

0
IQueryable<ShowMedicineViewModel> query; 
List<ShowMedicineViewModel> medic = new List<ShowMedicineViewModel>(); 
var medicineInfo = _dbContext.medicine_details.Where(m => (m.Medicine_name.StartsWith(medicinename)) && (m.Medicine_type == medicinetype)).ToList(); 

List<string> TotalMedicine = new List<string>(); 

var results = (medicineInfo.OrderBy(x => x.id) 
       .Skip((pages - 1) * 2) 
       .Take(2)); 


Parallel.ForEach(results, item => 
{ 
    var temp = Mapper.DynamicMap<medicine_details, ShowMedicineViewModel>(item); 

    medic.Add(temp); 
}); 

Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); 
dictionary2.Add("CurrentPage", pages); 
dictionary2.Add("TotalPages", medicineInfo.Count()/2 < 1 ? 1 : medicineInfo.Count()); 

Dictionary<string, object> dictionary = new Dictionary<string, object>(); 
dictionary.Add("Data", medic); 
dictionary.Add("Page", dictionary2); 

return dictionary;