Iniezione delle dipendenze con soluzione Entity Framework di livello n

11

Attualmente sto progettando una soluzione a più livelli che utilizza Entity Framework 5 (.net 4) come strategia di accesso ai dati, ma sono preoccupato su come incorporare l'integrazione delle dipendenze per renderla testabile / flessibile.

La mia attuale configurazione della soluzione è la seguente (la mia soluzione si chiama Alcatraz):

Alcatraz.WebUI : un progetto webform asp.net, l'interfaccia utente front-end, i progetti di riferimento Alcatraz.Business e Alcatraz.Data.Models .

Alcatraz.Business : un progetto di libreria di classi, contiene la logica aziendale, i progetti di riferimento Alcatraz.Data.Access , Alcatraz.Data.Models

Alcatraz.Data.Access : un progetto di libreria di classi, ospita AlcatrazModel.edmx e AlcatrazEntities DbContext, fa riferimento a progetti Alcatraz.Data.Models .

Alcatraz.Data.Models : un progetto di libreria di classi, contiene POCO per il modello Alcatraz, nessun riferimento.

La mia visione del funzionamento di questa soluzione è che web-ui crei un'istanza di repository all'interno della business library, questo repository avrebbe una dipendenza (tramite il costruttore) di una stringa di connessione (non un'istanza di AlcatrazEntities ). Il web-ui conoscerebbe le stringhe di connessione del database, ma non che fosse una stringa di connessione del framework di entità.

Nel progetto Business:

public class InmateRepository : IInmateRepository
{
    private string _connectionString;

    public InmateRepository(string connectionString)
    {
        if (connectionString == null)
        {
            throw new ArgumentNullException("connectionString");
        }

        EntityConnectionStringBuilder connectionBuilder = new EntityConnectionStringBuilder();

        connectionBuilder.Metadata = "res://*/AlcatrazModel.csdl|res://*/AlcatrazModel.ssdl|res://*/AlcatrazModel.msl";
        connectionBuilder.Provider = "System.Data.SqlClient";
        connectionBuilder.ProviderConnectionString = connectionString;

        _connectionString = connectionBuilder.ToString();
    }

    public IQueryable<Inmate> GetAllInmates()
    {
        AlcatrazEntities ents = new AlcatrazEntities(_connectionString);

        return ents.Inmates;
    }
}

Nell'interfaccia utente web:

IInmateRepository inmateRepo = new InmateRepository(@"data source=MATTHEW-PC\SQLEXPRESS;initial catalog=Alcatraz;integrated security=True;");

List<Inmate> deathRowInmates = inmateRepo.GetAllInmates().Where(i => i.OnDeathRow).ToList();

Ho alcune domande correlate su questo design.

  1. Questo progetto ha senso anche in termini di funzionalità di Entity Frameworks? Ho sentito che il framework Entity utilizza già lo schema Unità di lavoro, sto semplicemente aggiungendo un altro strato di abstract inutilmente?

  2. Non voglio che il mio web-ui comunichi direttamente con Entity Framework (o che faccia riferimento ad esso), voglio che tutto l'accesso al database passi attraverso il livello aziendale, perché in futuro avrò più progetti che utilizzano lo stesso livello aziendale (servizio Web, applicazione Windows, ecc.) e voglio mantenerlo / aggiornarlo facilmente avendo la logica aziendale in un'area centrale. È un modo appropriato per raggiungere questo obiettivo?

  3. Il livello aziendale dovrebbe contenere anche repository o dovrebbe essere contenuto nel livello di accesso? Se dove sono a posto, passa una stringa di connessione di una buona dipendenza da assumere?

Grazie per aver trovato il tempo di leggere!

    
posta Matthew 01.09.2012 - 05:56
fonte

2 risposte

11

Il modo in cui stai facendo DI è sbagliato.

Innanzitutto, la stringa di connessione appartiene al livello dati. O nel file web.config.

La prossima astrazione con cui si tratterà è DbContext, non una stringa di connessione. I tuoi repository non dovrebbero conoscere le stringhe di connessione. La tua logica di business non conoscerà DbContext ecc.

La tua interfaccia utente non avrà idea e non creerà un'istanza per qualsiasi cosa relativa a EF.

Risposte concrete ai tuoi punti:

  1. Non aggiungere astrazioni, finché non hai familiarità con EF. Aggiunge già buone astrazioni come UoW, query, utilizzo di POCO ecc.

  2. Affinché DI funzioni, hai una Radice di composizione che fa riferimento a tutti i componenti necessari. Questo potrebbe o potrebbe non essere nel progetto WebUI. Se non lo è, dovresti aspettarti che non faccia riferimento a EF o a qualsiasi altra tecnologia relativa ai dati.

  3. Fermati qui. Smetti di aggiungere astrazioni alle astrazioni. Inizia con un'architettura diretta e "ingenua" e sviluppala nel tempo.

Le astrazioni sono uno strumento per affrontare la complessità. Assenza di complessità significa che non sono necessarie (ancora) astrazioni.

    
risposta data 01.09.2012 - 21:01
fonte
4

Alcuni commenti rapidi. Personalmente, probabilmente non avrei passato una stringa di connessione. Se mai, proverei a creare interfacce forse per i repository e semplicemente a passare le interfacce in giro? I repository implementano o espongono un'interfaccia IOW.

In questo modo non è necessario che l'evento sia un database che implementa i tuoi repository. potrebbero essere una cache in memoria o qualsiasi altra cosa. Forse allora potresti usare una sorta di framework di dipendenza per istanziare anche questi?

Quindi in risposta ad alcune delle tue domande:

  1. Sì, penso che sia ok
  2. Avrei ancora l'interfaccia utente riferimento al progetto EF e alle interfacce di riferimento del livello commerciale implementate dal livello del repository EF. In questo modo, altri progetti potrebbero ancora utilizzare gli stessi assiemi ma hanno la flessibilità di poterli sostituire, se lo desideri?
  3. hmmm, Probabilmente i repository nel livello di accesso ma implementano una definizione dell'interfaccia esposta nel livello aziendale ??

Questi sono solo alcuni pensieri su cui riflettere.

    
risposta data 01.09.2012 - 08:28
fonte

Leggi altre domande sui tag