Soluții - PC Magazine Romania, Iulie 2004
Servicii Web - Transferul eficient al datelor
Vasile Marița
Acest articol prezintă câteva aspecte care trebuie analizate pentru obținerea
unui transfer de date eficient între un serviciu web și consumatorii acestuia,
deasemenea este prezentată o metodă interesantă pentru minimizarea redundanței
în datele transmise.
Un serviciu web este un modul software capabil să furnizeze o anumită funcționalitate,
această funcționalitate este disponibilă unui număr oricât de mare de utilizatori.
Informația este accesibilă pe baza utilizării unor standarde specifice Internet
cum ar fi XML și HTTP. Prezentând foarte plastic serviciile web comparativ cu
aplicațiile web, Don Box spune: "Traditional Web pages and applications
target carbon-based life forms (humans). Web Services target silicon-based life
forms (software agents)".
Serviciile web sunt destinate cu precădere expunerii funcționalității către
exterior, totuși tehnologia poate fi utilizată cu success și în cadrul unor
aplicații Intranet. Protocoalele deschise pe care se bazează, XML și HTTP, fac
posibilă interacțiunea între aplicații implementate pe platforme diferite (Windows
- Win32, .NET, Linux, Java).
Serviciile web pot implementa funcționalități diverse, fiecare având anumite
cereințe în ce privește dimensiunea transfer de date. Pentru a obține un randament
cât mai bun al transferului de date, înspre și dinspre serviciul web, se impune
o analiză atentă a datelor de transferat.
Printre factori de care trebuie ținut seama se numară: efortul CPU pentru pregătirea
datelor, volumul de muncă pentru implementare, redundanța în date, efortul CPU
și de implementare pentru prelucrarea datelor.
În continuare prezentăm o metodă interesantă pentru reducerea volumului de
date transmis. Vom folosi ca referință un serviciu web dezvoltat peste platforma
.NET, în limbajul C#.
Presupunem că serviciul web furnizează un catalog cu titlurile de carte disponibile
la o anumită editură.
Informația se găsește pe serverul editurii într-o bază de date care conține
printre altele următoarele tabele:
Pornind de la presupunerea că o rețea de distribuție de carte dorește afișarea
pe sit-ul ei a unei liste de titluri am putea implementa un serviciu web care
să furnizeze lista de titluri în așa fel încât fiecare titlu să fie complet
descris.
Pentru a sublinia ideea eliminării redundanței prezentăm în continuare două
alternative.
Soluția 1
[WebMethod] public DataSet ListaTitluri() { string strSQL = "SELECT t.nPK_ID, t.sNumeTitlu, a.sNumeAutor, a.sPrenumeAutor, a.sBiografie FROM dbo.tbTitluri t INNER JOIN dbo.tbAutori a ON t.nFK_Autor = a.nPK_ID"; DataSet dsResult = SqlHelper.ExecuteDataset (CONNECTION_STRING, CommandType.Text,strSQL ); return dsResult; }
Metoda este sinonimă cu obținerea unui select dintr-un view
SQL care reunește cele două tabele.
Vom observa însă o cantitate de informație redundantă care va fi transmisă
clientului. Pentru a evita acest neajuns putem transmite informația cerută într-un
dataset care conține cele două tabele relaționate.
Soluția 2
Scriem urmatoarea procedură stocată:
CREATE PROCEDURE dbo.sp_GetTitluri AS SET NOCOUNT ON SELECT * FROM tbTitluri SELECT * FROM tbAutori RETURN Implementăm serviciul web: [WebMethod] public DataSet ListaTitluri2() { const string TABLE_TITLURI = "tbTitluri"; const string TABLE_AUTORI = "tbAutori"; DataSet dsResult = SqlHelper.ExecuteDataset (CONNECTION_STRING, CommandType.StoredProcedure,"sp_GetTitluri", null);
// Dam nume relevante tabelelor dsResult.Tables[0].TableName = TABLE_TITLURI; dsResult.Tables[1].TableName = TABLE_AUTORI; // Definim o relatie intre cele doua // tabele pe baza capurilor titluri.FK_Autor si // autori.nPK_ID dsResult.Relations.Add("TitluriAutori", dsResult.Tables[TABLE_AUTORI].Columns["nPK_ID"], dsResult.Tables[TABLE_TITLURI].Columns ["nFK_Autor"]); return dsResult; }
Aplicația care folosește acest serviciu web va implementa:
EdituraOnLineService wsEditura = new EdituraOn LineService(); DataSet dsTitluri = wsEditura.ListaTitluri2(); wsEditura.Dispose(); wsEditura = null; // Adaugare campuri calculate
if (null != dsTitluri) { DataColumn newColumn = new DataColumn ("colAuthorPrenume"); newColumn.Expression= "Parent(TitluriAutori).sPrenumeAutor"; dsTitluri.Tables["tbTitluri"].Columns.Add (newColumn); newColumn = new DataColumn("colAuthorNume"); newColumn.Expression = "Parent(TitluriAutori). sNumeAutor"; dsTitluri.Tables["tbTitluri"].Columns.Add (newColumn); // Afisam tabela titluri intr-un DataGrid dgMain.DataSource = dsTitluri.Tables["tbTitluri"]; }
Esențial este modul în care se construiesc expresiile care vor fi evaluate
în coloanele noi.
În relația TitluriAutori, definită pe DataSet la server, tabela tbTitluri este
slave iar tabela tbAutori este master, ca urmare pentru fiecare rând din tabela
tbTitluri se va evalua rândul părinte Parent(TitluriAutori).sNumeAutor
din tabela master, punctat de relația Parent(TitluriAutori).sNumeAutor,
din rândul astfel obținut se citește valoarea câmpului Parent(TitluriAutori).sNumeAutor.
Se observă astfel că putem obține tabela tbTitluri similară celei din soluția
1, dar eliminând redundanța transmiterii informației despre autor. În plus informația
despre titluri și informația despre autori fiind izolată, putem beneficia de
o mai mare flexibilitate de manipulare a acesteia.
Trebuie să menționăm că metoda funcționează foarte bine pentru aplicații client
dezvoltate cu .NET (ADO.NET), pe alte platforme generarea coloanelor calculate
pe baza relațiilor putând induce un efort suplimentar de dezvoltare.
Referința:
http://msdn.microsoft.com/webservices/
http://msdn.microsoft.com/library/default.asp?url=
/library/en-us/cpref/html/frlrfSystemDataDataColumnClassExpressionTopic.asp
|