Oggetti business all'interno di un livello di accesso ai dati


12

Quindi ho creato un livello di accesso ai dati tramite TDD e ho affrontato un po 'di preoccupazione. Preferirei non iniziare sulla strada sbagliata, quindi ho pensato di chiedere a voi ragazzi di vedere se i miei pensieri erano in linea con un'architettura pulita.

I metodi all'interno del mio livello di accesso ai dati (in breve DAL) sono piuttosto semplici. Sono in linea con le procedure memorizzate nel database (nessun altro modo per richiamarlo per mantenere le cose pulite) e contengono gli stessi parametri delle procedure. Si connettono quindi al database e restituiscono il risultato della query. Ecco un esempio:

public int DeleteRecord(int recordId)
{
    recordId.RequireThat("recordId").NotZeroOrLess();

    List<SqlParameter> parameters = new List<SqlParameter>();
    parameters.Add(new SqlParameter { ParameterName = "@RecordId", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Input, Value = recordId});

    return this.ExecuteNonQuery("DeleteRecord", parameters.ToArray());
}

Questo funziona perfettamente per questo tipo di metodo perché non sto facendo nulla di significativo con il set di risultati. Voglio solo assicurarmi che il comando abbia funzionato, quindi restituirò il risultato della non query, che è solo le righe interessate, e posso verificare la logica usando quel numero.

Tuttavia, diciamo in un altro metodo DAL, voglio caricare un record. La mia procedura di caricamento verrà eseguita selectssu un gruppo di tabelle e restituirà un DataSet, ma sto combattendo con il fatto che il mio DAL debba creare gli oggetti business all'interno del metodo usando il DataSet, o se i miei oggetti business stessi dovrebbero avere solo un Load()metodo che ottiene il DataSetdal DAL, e quindi sostanzialmente si riempie.

Farlo attraverso il DAL comporterebbe meno logica negli Business Objects (anche se questa è solo una logica selezionata, è comunque logica), ma affollerebbe un po 'il DAL e lo farebbe sentire come se stesse davvero facendo qualcosa che non dovrebbe sto facendo.

Che cosa ne pensate?


Perché non hai usato Entity Framework?
jfrankcarr,

@jfrankcarr - Ad essere sincero, principalmente perché non ho familiarità con esso come dovrei essere. Avrei comunque bisogno di rielaborare le mie tabelle e aggiungere le chiavi esterne appropriate, ecc. In modo che Entity Framework riconoscesse correttamente le relazioni. Solo per curiosità, se lo stessi usando, farei solo tutta la selezione usando il framework con gli stessi Business Objects, o ci sarebbe ancora una decisione su dove porre quelle query LINQ?

Consiglierei di prendere il tempo per imparare EF. All'inizio può sembrare un po 'scoraggiante, specialmente quando si cerca di adattarlo a un database esistente che presenta alcuni problemi di progettazione preesistenti, ma ne vale la pena.
jfrankcarr,

Puoi anche guardare NHibernate se vuoi cercare un'altra opzione.
Don 01001100,

@jfrankcarr - Lo esaminerò sicuramente, ma come si adatta a un'applicazione di accesso ai dati multilivello? Il framework dell'entità stesso sarebbe implementato all'interno del DAL stesso, o all'interno di un altro livello o persino degli stessi Business Objects?

Risposte:


4

Il DAL dovrebbe restituire i tuoi oggetti dati

Idealmente, il DAL dovrebbe essere un oggetto "scatola nera", che il codice dell'applicazione può utilizzare per richiedere un oggetto dati o manipolare oggetti dati esistenti. A volte c'è un altro livello messo tra il DAL e il codice dell'applicazione chiamato il Repository, che separa ulteriormente i due livelli, anche se questo non è sempre necessario.

Inoltre, di solito non si desidera che i propri oggetti business siano in grado di creare se stessi. Ciò può causare falle nella sicurezza in cui qualcuno può utilizzare la tua libreria e creare una nuova istanza del tuo oggetto richiamandolo .Load(someId), che unisce due livelli che dovrebbero essere completamente separati.

Inoltre, non consiglio di fornire un .Load(DataSet ds)metodo perché se la definizione del set di dati cambia, dovrai dare la caccia agli oggetti dati che usano quel set di dati e modificarli. È più semplice conservare tutto il codice di accesso ai dati in un unico posto, quindi se si modifica la query di accesso ai dati, è necessario modificare solo il livello DAL.


Non sono sicuro di come si possa fare affidamento su un livello per "restituire l'oggetto corretto" se la definizione di "oggetto corretto" è contenuta in un altro livello.
TMN,

@TMN Era scritto male. Ho modificato un po 'la formulazione perché hai ragione, il codice dell'app dovrebbe sapere che tipo di oggetto chiede.
Rachel,

@Rachel - Gotcha. Quindi consiglieresti che il DAL restituisca un'istanza di qualunque sia il mio stesso Business Object, giusto? Ero un po 'confuso dalla tua formulazione di "oggetti dati", ma penso di capirlo. In questo modo, il mio codice potrebbe richiedere un oggetto business da qualsiasi luogo abbia bisogno (non attraverso loro stessi), semplicemente chiamando BusinessObject bo = DAL.LoadRecord(id);- suono giusto? La logica per mappare la query sul BO stesso sarebbe contenuta nel DAL, e solo lì.

1
@Scott È corretto, anche se chiamerei il metodo DAL in modo simile Getinvece che Load, comeCustomer c = DAL.GetCustomer(id);
Rachel,

2

Il mio metodo, anche prima di LINQ-To-SQL e Entity Framework, era di avere un'interfaccia e una libreria di classi astratte che fornissero un "contratto scritto" per la comunicazione tra i diversi livelli dell'app. Questo a volte viene chiamato ontologia , una definizione per un dominio di lavoro. Tutto ciò che è passato tra i livelli ha utilizzato questo "contratto".

Non mi piace l'idea di passare oggetti dataset grezzi dal livello dati al livello aziendale. Ho riscontrato questo risultato in una serie di problemi, in particolare quando si integrano origini dati legacy. Può anche rendere molto difficile per le nuove persone che entrano in un progetto capire da dove provengono i dati. Infine, richiede che il tuo livello aziendale si occupi della gestione dei dati direttamente dal DB, il che può portare a complicazioni lungo la strada.

Il codice di esempio che hai avuto è simile al codice che avevo prima di LINQ. Avevo una classe di funzioni DB comune che ho usato all'interno dei miei oggetti DAL. Le classi DAL leggono i dati e li inseriscono negli oggetti "contratto". I risultati scalari, come il tuo esempio di eliminazione, restituirebbero un valore, generalmente un valore booleano.


1
"Non mi piace l'idea di passare oggetti dataset grezzi dal livello dati al livello aziendale." Questo. Mille volte, questo.
Joshua Smith,

@jfrankcarr - Il mio DAL in realtà implementa un'interfaccia, e ho in programma di avere interfacce per tutto ciò che trasferisce i dati da un livello all'altro, quindi penso che le nostre idee di modello corrispondano lì. Quindi mi consiglia di cambiare i metodi che stanno restituendo il risultato diretto delle ExecuteScalarquery per restituire valori che hanno più senso a un livello aziendale, come bool? Penso diversamente, questa è una risposta molto simile a quella di Rachel.

In genere restituisco un valore booleano per creare / aggiornare / eliminare chiamate a meno che non sia necessario il numero di record interessati. Ad esempio, potrei restituire un int se un proc memorizzato sta elaborando più righe ordine o qualcosa del genere.
jfrankcarr,

0

Il DAL dovrebbe restituire un set di dati. Quel set di dati restituito dovrebbe essere l'oggetto aziendale, non dovrebbe esserci nulla che tu debba fare ad esso oltre a verificare che abbia i dati previsti. Se hai bisogno di fare di più con esso, allora stai provando a fare troppo in una singola procedura memorizzata o non stai restituendo i dati correttamente nella procedura memorizzata.


0

Consiglierei che i tuoi oggetti business abbiano un costruttore per popolare se stessi da un set di risultati. Ciò rimuove l'accoppiamento tra il DAL e il livello aziendale. Se si desidera isolare completamente i due, creare una semplice mappa di coppie nome-colonna => dal set di risultati e passarlo al costruttore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.