J'ai un projet avec un certain nombre de classes différentes qui interrogent et modifient des données dans un ensemble commun de tables. J'ai créé un fichier .dbml qui nous fournit une classe DataContext. Ma question est de savoir si une seule instance du DataContext doit être utilisée par tous les objets, ou si plusieurs instances peuvent être utilisées en toute sécurité. Je m'interroge également sur la sécurité des threads dans le cas d'un DataContext unique, et sur la nécessité de synchroniser l'accès à ses méthodes.
Réponses
Trop de publicités?Rick Strahl a rédigé un article intéressant sur les possibilités qui s'offrent à vous : http://www.west-wind.com/weblog/posts/246222.aspx .
Voir aussi : LINQ to SQL - où se trouve votre DataContext ? .
Vous pouvez vouloir une stratégie légèrement différente pour chaque type de déploiement - web, bureau, service Windows...
En résumé, vos options sont :
- Global DataContext - dangereux dans les environnements multithreads (y compris les applications web). Rappelez-vous que les membres de l'instance ne sont pas garantis d'être thread-safe (de Bradley Grainger's réponse ci-dessus).
- DataContext par thread - compliqué. Si votre DataContext suit les modifications, vous devez vous assurer de les purger au moment opportun. L'instanciation, le stockage et la récupération du DataContext sont des tâches pénibles.
- DataContext par action atomique - vous perdez la possibilité de suivre les changements puisqu'un DataContext crée un objet tandis qu'un autre le met à jour ou le supprime. Attacher un objet de données à un nouveau DataContext peut ne pas fonctionner comme vous le souhaitez.
- DataContext par objet de données - cela semble inélégant car il faut s'occuper du DataContext lors de l'instanciation (créer et attacher) et de la mise à jour/suppression (le retirer de l'objet de données et l'utiliser).
J'ai opté pour un DataContext par objet de données. Ce n'est peut-être pas la solution la plus fantaisiste, mais elle fonctionne dans tous les environnements de déploiement.
J'utilise une nouvelle instance de DataContext pour chaque transaction.
La réutilisation d'anciennes instances peut s'avérer gênante et gonfle le contenu du DataContext, car tout élément ayant été chargé à un moment donné devra faire l'objet d'un suivi - votre application sera de plus en plus lente et sa mémoire sera saturée.
Si vous avez besoin d'un élément plus longtemps que pour une transaction, vous pouvez le détacher du DataContext en le clonant, et le rattacher ultérieurement à un nouveau DataContext frais en utilisant Attach().
Je peux même cloner un élément, l'envoyer sur le réseau avec WCF, le récupérer lors d'un appel ultérieur, l'attacher à un nouveau DataContext et enregistrer les changements (bien sûr, j'ai besoin d'une colonne d'horodatage pour cela).
La classe DataContext est suffisamment légère pour que vous puissiez l'instancier à l'infini. Cela simplifie les choses lorsqu'il s'agit d'accéder à des objets d'entité dans une seule méthode. Si vous devez accéder aux mêmes objets LINQ à partir de différentes classes et méthodes tout en les gardant attachés au DataContext à des fins de suivi, il est également possible de conserver une seule instance.
Le problème avec l'utilisation d'un seul objet de contexte de données est que vous pouvez avoir des problèmes si vous avez ajouté des changements à sa file d'attente, et que vous voulez faire un retour en arrière sur seulement algunos de ces changements en file d'attente.
C'est pourquoi j'utilise un objet de contexte de données pour chacune de mes classes - ma User
possède son propre contexte de données, ma classe Application
a la sienne, et ainsi de suite.
Ce modèle élimine la plupart des problèmes de retournement dans mes projets.
Il y a un sérieux problème avec les DataContexts partagés : Le cache d'identité devient problématique lors des transactions croisées. Par exemple, vous ajoutez une ligne à une table, SubmitChanges
, annuler la transaction, ajouter la même ligne à nouveau, SubmitChanges
, bam : "row already exists" exception.
Ainsi, plus la portée du DataContext est petite, mieux c'est. Nous nous en tenons généralement à un DataContext par fonction. Parfois, il est transmis à des sous-fonctions. Sinon, il devient plus probable de laisser l'état du DataContext sale.