Domanda

Mi chiedevo se si consiglia di passare un oggetto di connessione al database (ad altri moduli) o di lasciare che il metodo (nell'altro modulo) si occupi di configurarlo. Mi sto proponendo di lasciare che il metodo lo configuri in modo da non dover controllare lo stato della connessione prima di usarlo, e basta che il chiamante passi tutti i dati necessari al metodo di chiamata che sarebbe necessario per impostare la connessione.

È stato utile?

Soluzione

Personalmente mi piace usare connessioni strettamente mirate; aprirli in ritardo, usarli e chiuderli (in un blocco "usando", tutto all'interno del metodo locale). Il pool di connessioni si occuperà di riutilizzare la connessione nella maggior parte dei casi, quindi non vi è alcun reale sovraccarico in questo approccio.

Il vantaggio principale nel passare le connessioni usato è quello di poter passare la transazione; tuttavia, TransactionScope è un modo più semplice di condividere una transazione tra metodi .

Poiché le classi sono specifiche dell'implementazione, scrivo ciascuna per aprire la propria transazione nativa. Altrimenti, è possibile utilizzare i metodi factory ado.net per creare il tipo appropriato dal file di configurazione (il nome del provider).

Altri suggerimenti

Personalmente, mi piace archiviare uno stack della mia connessione aperta corrente e le transazioni in cima a Archiviazione locale thread utilizzando SetData e GetData. Definisco una classe che gestisce le mie connessioni al database e gli consento di utilizzare il modello dispose. Questo mi fa risparmiare la necessità di trasferire connessioni e transazioni, il che è qualcosa che penso ingombra e complica il codice.

Consiglio vivamente contro di lasciarlo ai metodi per aprire le connessioni ogni volta che hanno bisogno di dati. Condurrà a una situazione davvero brutta in cui è difficile gestire le transazioni in tutta l'applicazione e troppe connessioni vengono aperte e chiuse (conosco il pool di connessioni, è ancora più costoso cercare una connessione dal pool di quanto non lo sia per riutilizzare un oggetto)

Quindi finisco per avere qualcosa del genere (totalmente non testato):

class DatabaseContext : IDisposable {

    List<DatabaseContext> currentContexts;
    SqlConnection connection;
    bool first = false; 

    DatabaseContext (List<DatabaseContext> contexts)
    {
        currentContexts = contexts;
        if (contexts.Count == 0)
        {
            connection = new SqlConnection(); // fill in info 
            connection.Open();
            first = true;
        }
        else
        {
            connection = contexts.First().connection;
        }

        contexts.Add(this);
    }

   static List<DatabaseContext> DatabaseContexts {
        get
        {
            var contexts = CallContext.GetData("contexts") as List<DatabaseContext>;
            if (contexts == null)
            {
                contexts = new List<DatabaseContext>();
                CallContext.SetData("contexts", contexts);
            }
            return contexts;
        }
    }

    public static DatabaseContext GetOpenConnection() 
    {
        return new DatabaseContext(DatabaseContexts);
    }


    public SqlCommand CreateCommand(string sql)
    {
        var cmd = new SqlCommand(sql);
        cmd.Connection = connection;
        return cmd;
    }

    public void Dispose()
    {
        if (first)
        {
            connection.Close();
        }
        currentContexts.Remove(this);
    }
}



void Test()
{
    // connection is opened here
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 1"))
        {
            cmd.ExecuteNonQuery(); 
        }

        Test2(); 
    }
    // closed after dispose
}

void Test2()
{
    // reuse existing connection 
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 2"))
        {
            cmd.ExecuteNonQuery();
        }
    }
    // leaves connection open
}

A fini di test automatizzati, in genere è più semplice passarlo. Si chiama Iniezione delle dipendenze .

Quando è necessario scrivere test, è possibile creare un oggetto di connessione al database fittizio e passarlo al posto di quello reale. In questo modo, i test automatici non si baseranno su un database reale che deve essere ripopolato con i dati ogni volta.

Lavoro personalmente per centralizzare il più possibile l'accesso ai miei dati, tuttavia, se non è possibile, apro SEMPRE una nuova connessione nelle altre classi, in quanto trovo che ci siano troppe altre cose che possono ostacolare il passaggio l'oggetto di connessione effettivo.

Ecco un po 'più di approfondimento su questo problema. Ho una classe che gestisce le connessioni db e ho 2 classi che implementano un'interfaccia. Una delle classi è per SQL e l'altra è per OLAP. Il gestore è quello che sa quale connessione utilizzare, quindi potrebbe passare la connessione esatta al tipo o il tipo può creare la propria connessione.

È possibile passare oggetti di connessione senza alcun problema (ad esempio Microsoft Enterprise Library consente chiamate di metodo statiche che passano in una connessione) oppure è possibile gestirlo esternamente secondo la propria progettazione, non ci sono compromessi tecnici diretti.

Fai attenzione alla portabilità per non passare una connessione specifica se la tua soluzione verrà trasferita su altri database (il che significa che non passa una connessione SQL se prevedi di lavorare con altri database)

L'impostazione della connessione è potenzialmente costosa e potenzialmente aggiunge un round trip. Quindi, di nuovo, potenzialmente, il progetto migliore è passare l'oggetto di connessione.

Dico potenzialmente, perché se sei un'app Microsoft ADO, probabilmente stai utilizzando un pool di connessioni ....

Suggerirei di distinguere tra l'oggetto connessione e il suo stato (aperto, chiuso).

Puoi avere un solo metodo (o proprietà) che legge la stringa di connessione da web.config. L'utilizzo della stessa versione della stringa di connessione ogni volta garantisce il vantaggio del pool di connessioni.

Chiama quel metodo quando devi aprire una connessione. All'ultimo momento, dopo aver impostato tutte le proprietà SqlCommand, aprire la connessione, usarla e quindi chiuderla. In C #, è possibile utilizzare l'istruzione using per assicurarsi che la connessione sia chiusa. In caso contrario, assicurarsi di chiudere la connessione in un blocco finally.

Vorrei usare web.config

<configuration>
    <connectionStrings>
        <add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" />
        <add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" />
    </connectionStrings>
</configuration>

Quindi puoi fare riferimento da qualsiasi parte dell'applicazione

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top