Dins de la construcció d'un grid, en la part que toca a un ASHX, el que cal saber és la seva configuració i com funcionen la clsColumna i clsCampBBDD. No cal conèixer en detall aquesta funció de la clsHelper, però si ens agrada el codi com a mi, no està de més saber com funciona per dins. Tots el grids d'una aplicació fan servir aquesta funció, porto uns quants projectes a l'esquena fent-la servir, així que penso que està amortitzada i no he trobat bugs aparents, però si en trobo almenys al corregir-ho serveix per tots.
El primer que fa aquesta funció és recuperar els valors dels paràmetres que indiquen la pàgina, l'ordre, etc... aquest paràmetres els genera el grid automàticament a la part client, en la part servidora només els recuperem.
- sidx: camps pel que es fa l'ordenació.
- sord: sentit de la ordenació, ascendent o descendent.
- rows: número de files a recuperar.
- page: pàgina a recuperar.
- A més a més d'aquests paràmetres a la URL també es posen els camps i els corresponents valors que es fan servir per filtrar el resultats. Es recuperen també, venen donats a la StringCollection CampsClau.
Durant el procés de recuperar aquests valors també es munta una clau que identifica de forma única un grid, i l'estat en que es troba. Com estat en que es troba s'enten: la pàgina, ordre, número de registres, filtre aplicat etc... Aquesta clau es fa servir per consultar la cache. A la cache de grids s'accedeix mitjaçant aquesta clau, un identificador de grid i la taula sobre la que s'aplica. Les operacions d'INS, UPD i DEL, en cas de tenir cache que la taula es gestioni amb cache, esborren els registres de la taula de cache només d'aquesta taula en concret. Un muntada aquesta clau es mira la taula de cache, si es troba es recupera el JSON i s'envia directament. D'això s'anomena un "cache hit". Si no es troba (un "cache miss") es segueix processant normalment i es crida a la funció QUERY (aquesta al seu temps cridarà a la SP QUERY). La diferència entre operar amb cache o sense és molt gran quan es fan QUERYs contra taules de milions de registres ja que els usuaris acostumen a treballar habitualment amb el mateix subconjunt de dades, es a dir no tots els registres tenen la mateixa importància.
Un cop obtinguts els registres cal empaquetar els camps en els objectes clsGridRow corresponents, donant format a les dades en cas de que estigui informat el camp "Format".
Un cop fet això poc queda per fer. Convertir-ho a JSON. Si la taula es gestiona amb cache, aquest JSON cal guardar-lo, d'aquesta manera el proper cop hi haurà un "cache hit" (de fet només que l'usuari refresqui la pàgina ja farà un hit). Com sempre el codi:
public static string LoadGrid(clsDades TA, HttpRequest Req, StringCollection CampsClau,
List<clsColumna> ColumnesGrid, Dictionary<string, string> ValorsExtraCampsClau, string GridID)
{
bool Search = false;
int i = 0;
string Ordenacio = "";
string SentitOrdre = "";
int numRegistres = 0;
int numPag = 0;
int numTotalRegs = 0;
int numTotalPags = 1;
DataTable TBL;
DataRow DR;
Dictionary<string, string> Params = new Dictionary<string, string>();
Dictionary<string, string> ParamsCache = new Dictionary<string, string>();
clsGridRow GR;
string Valor = "";
decimal ValorDecimal = 0;
DateTime ValorDateTime;
clsCache Cache = new clsCache(TA.CadConnBBDD);
string Result = "";
StringBuilder URL = new StringBuilder();
if (Req["_search"] != null)
bool.TryParse(Req["_search"], out Search);
Ordenacio = Req["sidx"];
SentitOrdre = Req["sord"].ToUpper();
clsGridResponse Data = new clsGridResponse();
numRegistres = int.Parse(Req["rows"]);
numPag = int.Parse(Req["page"]);
foreach (string Clau in CampsClau)
{
if (!string.IsNullOrEmpty(Req[Clau]))
{
Params.Add(Clau, Req[Clau]);
URL.AppendFormat("-{0}-{1}", Clau, Req[Clau]);
}
else
{
if (ValorsExtraCampsClau != null)
{
if (ValorsExtraCampsClau.ContainsKey(Clau))
{
Params.Add(Clau, ValorsExtraCampsClau[Clau]);
URL.AppendFormat("-{0}-{1}", Clau, ValorsExtraCampsClau[Clau]);
}
}
}
}
if (TA.TeCache)
{
URL.AppendFormat("{0}{1}", Ordenacio.ToString(), SentitOrdre.ToString());
URL.AppendFormat("{0}{1}", Req["rows"], Req["page"]);
ParamsCache.Add("Taula", TA.NomTaula);
ParamsCache.Add("URL", URL.ToString());
ParamsCache.Add("GridID", GridID);
TBL = Cache.GET(ParamsCache);
if (TBL.Rows.Count != 0)
{
Result = TBL.Rows[0]["JSON"].ToString();
return Result;
}
}
Params.Add("PageSize", numRegistres.ToString());
Params.Add("PageNum", numPag.ToString());
Params.Add("SortColumn", Ordenacio + SentitOrdre);
TBL = TA.QUERY(Params, out numTotalRegs);
#if DEBUG
foreach (clsColumna ColumnaGrid in ColumnesGrid)
{
foreach (clsCampBBDD CampGridBBDD in ColumnaGrid.Camps)
{
if (!TBL.Columns.Contains(CampGridBBDD.Nom))
{
throw new Exception("ERROR: La columna " + CampGridBBDD.Nom + " no pertany a la taula del LoadGrid");
}
}
}
#endif
numTotalPags = numTotalRegs / numRegistres;
if (numTotalRegs % numRegistres != 0) numTotalPags++;
Data.total = numTotalPags.ToString();
Data.page = Req["page"];
for (i = 0; i < TBL.Rows.Count; i++)
{
GR = new clsGridRow();
DR = TBL.Rows[i];
foreach (clsColumna ColumnaGrid in ColumnesGrid)
{
Valor = "";
for (int j = 0; j < ColumnaGrid.Camps.Count; j++)
{
if (j != 0) Valor += ColumnaGrid.Separador;
if (!DR.IsNull(ColumnaGrid.Camps[j].Nom))
{
if (ColumnaGrid.Camps[j].Format != "")
{
switch (ColumnaGrid.Camps[j].Tipus)
{
case "System.DateTime":
ValorDateTime = (DateTime)DR[ColumnaGrid.Camps[j].Nom];
Valor += ValorDateTime.ToString(ColumnaGrid.Camps[j].Format);
break;
case "System.Decimal":
ValorDecimal = (Decimal)DR[ColumnaGrid.Camps[j].Nom];
Valor += ValorDecimal.ToString(ColumnaGrid.Camps[j].Format);
break;
}
}
else Valor += DR[ColumnaGrid.Camps[j].Nom].ToString();
}
else Valor += ColumnaGrid.Camps[j].ValorSiNull;
}
GR.cell.Add(Valor);
}
Data.rows.Add(GR);
}
Data.records = numTotalRegs.ToString();
Result = clsJSON.Serialize(Data);
if (TA.TeCache)
{
Params.Clear();
Params.Add("Taula", TA.NomTaula);
Params.Add("URL", URL.ToString());
Params.Add("GridID", GridID);
Params.Add("JSON", Result);
Cache.INS(Params);
}
return Result;
}
|