2010-03-31 4 views
2

J'ai commencé à travailler avec linq sur SQL il y a quelques semaines. Je suis vraiment fatigué de travailler avec le serveur SQL directement à travers les requêtes SQL (sqldatareader, sqlcommand et toutes ces bonnes choses). Après avoir entendu parler de linq to SQL et de mvc, j'ai rapidement déplacé tous mes projets vers ces technologies. Je m'attendais à ce que linq to SQL fonctionne plus lentement, mais il s'est avéré très rapide, surtout parce que j'ai toujours oublié de fermer mes connexions lorsque j'utilisais des lecteurs de données. Maintenant, je n'ai pas à m'inquiéter à ce sujet.linq: Performances SQL sur les applications Web fortement chargées

Mais il y a un problème qui me dérange vraiment. Il y a une page qui est demandée des milliers de fois par jour. Le système obtient des données au début, travaille avec et les met à jour. Principalement les mises à jour sont ++ @ - (augmenter et diminuer les valeurs). Je l'habitude de le faire comme ça

UPDATE table SET valeur = valeur + 1 WHERE ID = @ Je serais

Il a travaillé sans problème évidemment. Mais avec linq to SQL, les données sont prises au début, déplacées dans la classe, modifiées puis sauvegardées.

Stats.registeredusers ++; Db.submitchanges();

Disons qu'il y avait 100 000 utilisateurs. Linq dira "laissez-le être 100 001" au lieu de "laissez-le être augmenté de 1".

Mais si la valeur des utilisateurs a déjà été augmenté (ce qui se passe dans mon site tout le temps), alors LINQ sera comme oups, cette valeur est déjà 100 001. Tout ce que je vais jeter une exception »

Vous pouvez modifier ce comportement pour qu'il ne lève pas d'exception, mais il ne définira toujours pas la valeur à 100 002.

Comme je l'ai dit, ça m'est arrivé tout le temps, la valeur de stas a été augmentée deux fois par seconde En moyenne, j'ai simplement dû réécrire ce morceau de code avec le classique ado net

Donc, ma question est comment pouvez-vous résoudre le problème avec linq

Répondre

5

Pour ces types de "requêtes en écriture seule", j'utilise généralement une procédure stockée. Vous pouvez faire glisser la procédure stockée dans le concepteur et l'exécuter via la classe Linq to SQL DataContext (elle sera ajoutée en tant que méthode).

Désolé pour la réponse banale, mais c'est vraiment simple; pas besoin de finagle avec des objets ADO.NET SqlCommand et similaires, il suffit d'importer le SP et vous avez terminé. Ou, si vous voulez aller vraiment ad hoc, utilisez la méthode ExecuteCommand, comme dans:

context.ExecuteCommand("UPDATE table SET value = value + 1 WHERE ID = {0}", id); 

(Mais ne pas abuser de cela, il peut devenir difficile à maintenir car la logique n'est plus contenu dans votre instance DataContext Et avant que quiconque ne saute dessus en prétendant qu'il s'agit d'une vulnérabilité d'injection SQL, veuillez noter que ExecuteCommand/ExecuteQuery sont des méthodes intelligentes qui transforment ceci en une instruction/requête paramétrée.)

+0

Merci! Je n'ai même pas pensé aux procédures stockées. Ils fonctionneront très bien. Et je ne connaissais pas la méthode ExecuteCommand. Je vais trouver plus d'informations sur. Ce sera très utile pour moi - bien mieux que de tout réécrire à partir de zéro avec des commandes et des connexions. – Alex

4

Linq to Sql prend en charge la concurrence "optimiste" hors de la boîte. Si vous avez besoin d'un contrôle plus strict, vous pouvez ajouter une colonne Timestamp à votre table, et Linq to Sql utilisera cet horodatage pour resserrer la concurrence.

http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2008/07/01/10557.aspx

Cependant, comme Morten souligne dans les commentaires ci-dessous, cette solution ne va pas bien performer. Bien sûr, vous pouvez toujours utiliser ADO.NET pour mettre à jour la valeur, comme vous le faisiez auparavant; Cela n'affectera pas du tout le fonctionnement de vos requêtes Linq.

+0

Pourquoi le downvote? –

+0

Bien que vous puissiez argumenter que le contrôle des accès simultanés protège la valeur des statistiques, la solution suggérée fonctionnera très mal s'il y a plusieurs mises à jour de la table (en raison de fréquentes mises à jour avec des données périmées). La solution ADO.NET d'origine ne souffre pas de cette lacune car elle effectue une modification relative plutôt que d'écrire une valeur absolue. Pensez-y comme Interlocked.Increment vs "i + = 1". –

+0

@Morten: Comme je l'ai souligné dans un commentaire à l'OP, il pourrait toujours utiliser ADO.NET pour incrémenter la valeur, mais il veut utiliser Linq. Peut-être qu'une procédure stockée pourrait-elle être utilisée? –

0

Vous pouvez désactiver cette propriété sur la concurrence en changeant la valeur UpdateCheck:

http://msdn.microsoft.com/en-us/library/bb399394(v=VS.90).aspx

Messy si vous utilisez le code généré et le concepteur, mais je pense que c'est la seule façon de le faire.

+0

Si vous désactivez complètement la concurrence, vous risquez une condition de concurrence dans laquelle la valeur incrémentée a déjà été incrémentée par un autre thread pendant que votre thread tente de l'incrémenter. Le compte résultant sera désactivé par un. –

Questions connexes