.NET Entity Framework et les transactions
Être de nouveau à l'Entity Framework, je suis vraiment plutôt coincé sur la façon de procéder avec cet ensemble de questions. Sur le projet que je suis en train de travailler, l'ensemble du site est fortement intégré avec le modèle EF. Au premier abord, l'accès à l'EF contexte a été contrôlée à l'aide d'une Injection de Dépendance de programme d'amorçage. Pour des raisons opérationnelles, nous n'avons pas été en mesure d'utiliser un DI bibliothèque. J'ai enlevé ce et utilisé un modèle de différentes instances de l'objet de contexte où nécessaire. J'ai commencé à faire de l'exception suivante:
Type " XXX " a été cartographié plus d'une fois.
Nous sommes arrivés à la conclusion que les différentes instances du contexte ont été à l'origine de ce problème. J'ai ensuite extraites du contexte de l'objet en une seule instance statique qui a été consulté par chaque thread/page. Je suis maintenant l'un de plusieurs exceptions sur les transactions:
Nouvelle transaction n'est pas autorisée, car il y a d'autres threads d'exécution
dans la session.L'opération de transaction ne peut pas être effectuée parce qu'il y a
les demandes en attente de travailler sur cette transaction.ExecuteReader nécessite la commande pour une transaction lorsque l'
connexion affectés à la commande est en attente de la transaction locale.
La Transaction de propriété de la commande n'a pas été initialisé.
Le dernier de ces exceptions s'est produite sur une opération de chargement. Je ne cherche pas à sauver le contexte de l'état vers la Db sur le thread qui a échoué. Il y avait un autre thread d'exécution d'une telle opération cependant.
Ces exceptions sont intermittentes au mieux, mais j'ai réussi à obtenir le site d'entrer dans un état où les nouvelles connexions ont été refusées en raison d'une opération de verrouillage. Malheureusement, je ne trouve pas les détails de l'exception.
Je suppose que ma première question est de savoir si le modèle EF être utilisé à partir d'une statique instance unique? Aussi, est-il possible de supprimer la nécessité pour les transactions en EF? J'ai essayé d'utiliser un TransactionScope
objet sans succès...
Pour être honnête, je suis coincé ici, et ne peut pas comprendre pourquoi (ce qui devrait être) assez simples opérations sont à l'origine d'un tel problème...
- Connexes: stackoverflow.com/questions/10585478/...
- C'est dommage que vous ne pouvez pas utiliser un CIO programme d'amorçage, parce que la solution avec Ninject serait de lier un "bien commun" de l'instance à la demande de la portée, comme d'autres l'ont suggéré:
kernel.Bind<IRepository<SomeModel>>().To<EfGenericRepository<SomeModel, YourDbContext>>().InRequestScope();
-- l'important étantInRequestScope
Vous devez vous connecter pour publier un commentaire.
La création d'une Entité globale Cadre
DbContext
dans une application web est très mauvais. LeDbContext
classe n'est pas thread-safe (et de même pour Entity Framework v1 estObjectContext
classe). Elle est construite autour du concept de la unité de travail et cela signifie que vous utilisez pour faire fonctionner un seul cas d'utilisation: ainsi, pour une opération commerciale. Il est conçu pour traiter une requête unique.L'exception que vous obtenez arrive parce que pour chaque demande, vous créez une nouvelle opération, mais essayez d'utiliser la même
DbContext
. Vous avez de la chance que leDbContext
détecte et déclenche une exception, parce que maintenant vous avez trouvé que cela ne fonctionne pas.S'il vous plaît penser ce pourquoi cela ne peut pas fonctionner. Le
DbContext
contient un cache local des entités dans votre base de données. Il permet de faire un tas de changements et, enfin, de soumettre ces modifications à la base de données. Lors de l'utilisation d'un seul statiqueDbContext
, avec de multiples utilisateurs d'appelSaveChanges
sur cet objet, comment est-il censé savoir exactement ce que devrait être engagée et ce qui ne l'est pas?Car il ne sait pas, il vous fera économiser tous changements, mais à ce point une autre demande peut-être encore de faire des changements. Lorsque vous avez de la chance, soit EF ou votre base de données sera un échec, car les entités sont dans un état non valide. Si vous êtes malchanceux, les entités qui sont dans un état non valide sont correctement enregistré dans la base de données et vous pouvez trouver semaines plus tard, que votre base de données est plein de merde.
La solution à votre problème est de créer au moins un
DbContext
par demande. Si, en théorie, vous pourriez mettre en cache un contexte de l'objet dans la session de l'utilisateur, c'est aussi une mauvaise idée, parce que dans ce cas, leDbContext
généralement vivent trop longtemps, et contenir des données obsolètes (parce que son cache interne ne seront pas automatiquement actualisé).Notez également que le fait d'avoir un
DbContext
par thread est aussi mauvais que d'avoir une seule instance de l'application web entière. ASP.NET utilise un pool de threads qui signifie qu'une quantité limitée de threads sera créé au cours de la durée de vie d'une application web. Cela signifie essentiellement que cellesDbContext
instances seront, dans ce cas encore vivre pour la durée de vie de l'application, ce qui provoque les mêmes problèmes avec l'insipidité de données.Vous pourriez penser que le fait d'avoir un
DbContext
par thread est en fait thread-safe, mais ce n'est généralement pas le cas, puisque ASP.NET a un modèle asynchrone qui permet la finition des demandes sur un thread différent de celui où il a été commencé (et les versions les plus récentes de la MVC et Web API de même permettre à un nombre arbitraire de threads de s'occuper d'une seule requête dans l'ordre séquentiel). Cela signifie que le thread qui a commencé par une demande et a créé leObjectContext
peut devenir disponible pour traiter une autre demande long avant que la demande initiale terminée. Les objets utilisés dans cette demande cependant (comme une page web, de contrôleur ou de toute classe affaires), peut encore référence queDbContext
. Depuis le nouveau site web demande s'exécute dans le même thread, il obtiendra le mêmeDbContext
exemple comme quoi les vieux demande de l'aide. Ce nouveau cause des conditions de course dans votre application et de provoquer le même thread-les questions de sécurité comme ce que l'on globalDbContext
instance causes.Que vous consultez le "site" dans votre question, je suppose que c'est une application web. Les membres statiques exister qu'une seule fois pour l'ensemble de l'application, si vous utilisez un singleton de type modèle avec une seule instance du contexte de l'ensemble de l'application, toutes sortes de demandes vont être dans toutes sortes d'états à travers l'ensemble de l'application.
Une seule instance de contexte statique ne fonctionne pas, mais le contexte plusieurs instances par thread va être difficile tant que bien que vous ne pouvez pas mélanger et assortir les contextes. Ce que vous avez besoin est un contexte unique par thread. Nous l'avons fait dans notre application, à l'aide d'une injection de dépendance type de modèle. Notre BLL et DAL classes prendre le contexte comme un paramètre dans les méthodes, de cette façon, vous pouvez faire quelque chose comme ci-dessous:
Si vous avez besoin d'appeler d'autres BLL/DAL méthodes au sein de votre mise à jour (ou quelle que soit la méthode que vous avez choisi) il vous suffit de passer le même contexte autour. De cette façon, les mises à jour/insertions/suppressions sont atomiques, tout au sein d'une seule méthode est d'utiliser la même instance de contexte, mais cette instance n'est pas utilisé par d'autres threads.