Question

Je me demandais s'il était recommandé de transmettre un objet de connexion à la base de données (à d'autres modules) ou de laisser la méthode (dans l'autre module) s'occuper de son paramétrage. Je suis plutôt enclin à laisser la méthode la paramétrer pour ne pas avoir à vérifier l'état de la connexion avant de l'utiliser, et simplement à l'appelant de transmettre toutes les données nécessaires à la méthode d'appel qui seraient nécessaires pour établir la connexion.

Était-ce utile?

La solution

Personnellement, j'aime utiliser des connexions à portée étroite; ouvrez-les tardivement, utilisez-les et fermez-les (dans un bloc "utilisant", le tout selon la méthode locale). Le regroupement de connexions permettra dans la plupart des cas de réutiliser la connexion. Il n’ya donc pas de réel surcoût dans cette approche.

Le principal avantage de passer des connexions était autrefois de manière à pouvoir transférer la transaction; Cependant, TransactionScope est un moyen plus simple de partager une transaction entre des méthodes. .

Puisque les classes sont spécifiques à l'implémentation, j'écrirais chacune d'elles pour ouvrir sa propre transaction native. Sinon, vous pouvez utiliser les méthodes de fabrique ado.net pour créer le type approprié à partir du fichier de configuration (le nom du fournisseur).

Autres conseils

Personnellement, j'aime bien stocker une pile de ma connexion ouverte actuelle et de mes transactions au-dessus de Stockage local des threads à l'aide de SetData et GetData. Je définis une classe qui gère mes connexions à la base de données et lui permet d'utiliser le modèle de disposition. Cela évite de passer des connexions et des transactions, ce qui, à mon avis, encombrerait et compliquerait le code.

Je recommande vivement de ne pas laisser aux méthodes le soin d'ouvrir des connexions chaque fois qu'elles ont besoin de données. Cela conduira à une très mauvaise situation dans laquelle il est à la fois difficile de gérer les transactions dans l’application et où trop de connexions sont ouvertes et fermées (je connais le pooling de connexion, il est toujours plus coûteux de rechercher une connexion dans le pool qu’elle ne l’est. pour réutiliser un objet)

Je finis donc par avoir quelque chose dans ce sens (totalement non testé):

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
}

À des fins de test automatisé, il est généralement plus facile de le transmettre. Cette opération s'appelle injection de dépendance . .

Lorsque vous devez écrire des tests, vous pouvez créer un objet de connexion à une base de données fictive et le transmettre à la place du véritable. Ainsi, vos tests automatisés ne s'appuieront pas sur une base de données réelle qui doit être repeuplée avec des données à chaque fois.

Je travaille personnellement pour centraliser autant que possible l'accès à mes données. Toutefois, si ce n'est pas possible, j'ouvre TOUJOURS une nouvelle connexion dans les autres classes, car je constate qu'il y a trop d'autres choses qui peuvent gêner la transmission. l'objet de connexion réel.

Voici un petit aperçu de ce problème. J'ai une classe qui gère les connexions à la base de données et 2 classes qui implémentent une interface. Une des classes est pour SQL et l'autre est de OLAP. Le gestionnaire est celui qui sait quelle connexion utiliser, il peut donc transmettre la connexion exacte au type, ou le type peut créer sa propre connexion.

Vous pouvez transmettre des objets de connexion sans aucun problème (par exemple, Microsoft Enterprise Library autorise les appels de méthode statiques en passant une connexion) ou vous pouvez le gérer de manière externe jusqu’à votre conception, il n’existe pas de compromis techniques directs.

Veillez à ce que la portabilité ne transmette pas une connexion spécifique si votre solution doit être transférée vers d'autres bases de données (ce qui signifie que vous ne transmettez pas une connexion SqlConnection si vous prévoyez de travailler avec d'autres bases de données)

La configuration de la connexion est potentiellement coûteuse et ajoute potentiellement un aller-retour. Donc, encore une fois, potentiellement, la meilleure conception consiste à transmettre l'objet de connexion.

Je dis potentiellement, car si vous êtes une application Microsoft ADO, vous utilisez probablement un pool de connexions ....

Je vous suggérerais de faire la distinction entre l'objet de connexion et son état (ouvert, fermé).

Vous pouvez avoir une seule méthode (ou propriété) qui lit la chaîne de connexion à partir de web.config. Utiliser la même version de la chaîne de connexion à chaque fois garantit que vous profiterez du regroupement de connexions.

Appelez cette méthode lorsque vous devez ouvrir une connexion. Au tout dernier moment, après avoir défini toutes les propriétés SqlCommand, ouvrez la connexion, utilisez-la, puis fermez-la. En C #, vous pouvez utiliser l'instruction using pour vous assurer que la connexion est fermée. Sinon, assurez-vous de fermer la connexion dans un bloc enfin.

Je voudrais utiliser le 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>

Ensuite, vous pouvez le référencer de n'importe où dans l'application

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top