Per raons que no arribo a entendre a vegades hi ha projectes on el client no vol stored procedures. O potser es requereix fer una migració de dades puntual i no es volen deixar un munt d'stored procedures que ningú farà servir més endevant. Aleshores tota la feina del generador d'storeds no serveix, hi ha que fer servir una altra tècnica.
Per això he mogut uns quants mètodes del generador d'stored a la clsDades, així la clsDades genera SQL sobre la marxa. Es a dir, aprofitant la informació sobre els camps de la taula de la que disposa una clase derivada (nom, longitud i tipus de les columnes) la clsDades ha incorporat unes funcions que generen inserts, updates i deletes sobre la marxa.
Estan disponibles en dos sabors, la que admet DataRow i la que admet Dictionary's, són calcades amb petites modificacions. Començaré pel constructor d'INSerts i deixaré per altres posts els UPD i DEL.
public string INS_Builder(Dictionary<string, string> DR, bool IdentityInsert)
{
DateTime ValorDateTime;
StringBuilder SB = new StringBuilder();
SB.AppendFormat("INSERT INTO {0} (", NomTaula);
for (int i = 0; i < CampsResultat.Length; i++)
{
if (!CampsResultat[i].PK || IdentityInsert)
{
SB.Append(CampsResultat[i].NomCamp + ", ");
}
}
SB.Remove(SB.Length - 2, 2);
SB.Append(") VALUES (");
for (int i = 0; i < CampsResultat.Length; i++)
{
if (!CampsResultat[i].PK || IdentityInsert)
{
if (!DR.ContainsKey(CampsResultat[i].NomCamp))
{
throw new Exception("La fila no té el camp " + CampsResultat[i].NomCamp);
}
if (string.IsNullOrWhiteSpace(DR[CampsResultat[i].NomCamp]))
{
if (!CampsResultat[i].Nulable)
throw new Exception("Camp " + CampsResultat[i].NomCamp + " no admet valors NULLs");
else
{
SB.Append("NULL, ");
}
}
else
{
switch (CampsResultat[i].Tipus)
{
case Tipus.nchar:
case Tipus.nvarchar:
case Tipus.chr:
case Tipus.varchar:
SB.Append("'" + DR[CampsResultat[i].NomCamp].Replace("'", "''") + "', ");
break;
case Tipus.datetime:
case Tipus.date:
case Tipus.time:
ValorDateTime = DateTime.Parse(DR[CampsResultat[i].NomCamp]);
SB.Append("'" + FDateSQL(ValorDateTime) + "', ");
break;
case Tipus.dec:
SB.Append(DR[CampsResultat[i].NomCamp].Replace(",", ".") + ", ");
break;
case Tipus.bit:
if (DR[CampsResultat[i].NomCamp].ToLower() == "true" ) SB.Append("1, ");
else SB.Append("0, ");
break;
default:
SB.Append(DR[CampsResultat[i].NomCamp] + ", ");
break;
}
}
}
}
SB.Remove(SB.Length - 2, 2);
SB.Append(")");
return SB.ToString();
}
public string INS_Builder(DataRow DR, bool IdentityInsert)
{
DateTime ValorDateTime;
Boolean ValorBool;
StringBuilder SB = new StringBuilder();
SB.AppendFormat("INSERT INTO {0} (", NomTaula);
for (int i = 0; i < CampsResultat.Length; i++)
{
if (!CampsResultat[i].PK || IdentityInsert)
{
SB.Append(CampsResultat[i].NomCamp + ", ");
}
}
SB.Remove(SB.Length - 2, 2);
SB.Append(") VALUES (");
for (int i = 0; i < CampsResultat.Length; i++)
{
if (!CampsResultat[i].PK || IdentityInsert)
{
if (!DR.Table.Columns.Contains(CampsResultat[i].NomCamp))
{
throw new Exception("La fila no té el camp " + CampsResultat[i].NomCamp);
}
if (DR.IsNull(CampsResultat[i].NomCamp))
{
if (!CampsResultat[i].Nulable)
throw new Exception("Camp " + CampsResultat[i].NomCamp + " no admet valors NULLs");
else
{
SB.Append("NULL, ");
}
}
else
{
switch (CampsResultat[i].Tipus)
{
case Tipus.nchar:
case Tipus.nvarchar:
case Tipus.chr:
case Tipus.varchar:
SB.Append("'" + DR[CampsResultat[i].NomCamp].ToString().Replace("'", "''") + "', ");
break;
case Tipus.datetime:
case Tipus.date:
case Tipus.time:
ValorDateTime = DR.Field<DateTime>(CampsResultat[i].NomCamp);
SB.Append("'" + FDateSQL(ValorDateTime) + "', ");
break;
case Tipus.dec:
SB.Append(DR[CampsResultat[i].NomCamp].ToString().Replace(",", ".") + ", ");
break;
case Tipus.bit:
ValorBool = DR.Field<Boolean>(CampsResultat[i].NomCamp);
if (ValorBool) SB.Append("1, ");
else SB.Append("0, ");
break;
default:
SB.Append(DR[CampsResultat[i].NomCamp].ToString() + ", ");
break;
}
}
}
}
SB.Remove(SB.Length - 2, 2);
SB.Append(")");
return SB.ToString();
}
Cal tenir en compte que si després d'un INSERT es vol obtenir el valor d'una columna identitat cal fer servir la funció IDENT_CURRENT. Si es volen agrupar varies sentències SQL s'haurà de fer en un StringBuilder on es vagin acumulant. Les versions de INS/UPD que reben un Dictionary encaixen amb el Deserialitzador que retorna també un Dictionary. |