Stiamo cercando di trovare un modo per gestire il codice che crea SQL dinamico per la nostra applicazione, che è molto centrato sul database. Cose come Linq to SQL e Entity Framework sono fuori questione, quindi per favore non ci sono suggerimenti di questo tipo, il nostro percorso è stato definito per noi.
Il nostro obiettivo principale è la separazione di SQL dal resto del codice (business logic, ecc.).
In questo momento, stiamo pensando di utilizzare i metodi di estensione per ospitare l'SQL e di creare una sorta di oggetto di configurazione che gli sviluppatori possono utilizzare per definire come deve essere costruita la query (dettata dalla logica aziendale, al di fuori dell'estensione classe)
Quindi, ad esempio, ho un codice prototipo sotto. Gli sviluppatori installerebbero la Stringa di configurazione (come da regole aziendali) e la passeranno a GetSQL.
public static class LocationSql2Extension
{
public enum SelectFields
{
Default,
DefaultAnd_Description_LocationSize
}
public enum FilterBy
{
Default,
DefaultAnd_Description
}
public enum OrderBy
{
Default,
DefaultAnd_LocationType_LocationID_Description
}
public struct Configuration
{
public SelectFields SelectFields;
public FilterBy FilterBy;
public OrderBy OrderBy;
}
public static string GetSQL(this LocationService2 service, Configuration config)
{
string sqlSelectFields = string.Empty;
string sqlWhere = string.Empty;
string sqlOrderBy = string.Empty;
if (config.SelectFields == SelectFields.DefaultAnd_Description_LocationSize)
{
sqlSelectFields = ", Description, LocationSize";
}
if (config.FilterBy == FilterBy.DefaultAnd_Description)
{
sqlWhere = "WHERE L.Description = ?";
}
if (config.OrderBy == OrderBy.DefaultAnd_LocationType_LocationID_Description)
{
sqlOrderBy = ", L.LocationDescription";
}
string sql = string.Format(@"
SELECT L.LocationType, L.LocationId
{0}
FROM Location AS L
INNER JOIN GroupLoc AS GL
ON L.LocationType = GL.LocationType
AND L.LocationId = GL.LocationId
AND GL.SecLocLevel >= 4
AND GL.GroupId = ?
{1}
ORDER BY L.LocationType||L.LocationId
{2}
", sqlSelectFields, sqlWhere, sqlOrderBy);
return sql;
}
}
e per chiamare il codice precedente, abbiamo questo:
public class LocationService2
{
public string BuildSql()
{
var config = new LocationSql2Extension.Configuration();
//TODO: Add Business Logic to drive these values
config.SelectFields = LocationSql2Extension.SelectFields.Default;
config.OrderBy = LocationSql2Extension.OrderBy.DefaultAnd_LocationType_LocationID_Description;
config.FilterBy = LocationSql2Extension.FilterBy.DefaultAnd_Description;
return this.GetSQL(config);
}
}
Gli sviluppatori sarebbero liberi di configurare l'Enum come preferiscono, e questo è solo un semplice esempio. Non ci sentiamo a nostro agio con questo approccio Enum / Struct e stiamo cercando qualcosa di più generico per il quale gli sviluppatori possano lavorare facilmente, ma non è così generico da non rilevare errori in fase di progettazione. Questo è un semplice esempio e nel nostro sistema abbiamo alcune query molto grandi e complesse. Qualche suggerimento?