2010-08-12 17 views
2

J'ai 2 tables. Ce qui suit sont juste une version dépouillée de ces tables.Comment résoudre ce problème de procédure stockée

TableA 
Id <pk> incrementing 
Name varchar(50) 

TableB 
TableAId <pk> non incrementing 
Name varchar(50) 

Maintenant, ces tables ont une relation entre elles.

Scénario

utilisateur 1 vient à mon site et fait quelques actions (dans ce cas, ajoute des lignes au tableau A). Donc j'utilise une SqlBulkCopy toutes ces données dans le tableau A.

Cependant, j'ai besoin d'ajouter les données à la table B mais je ne connais pas les ID nouvellement créés dans la table A car SQLBulkCopy ne les retournera pas.

Je pense d'avoir une procédure stockée qui trouve tous les id qui n'existent pas dans le tableau B, puis les insérer dans.

INSERT INTO TableB (TableAId , Name) 
SELECT Id,Name FROM TableA as tableA 
WHERE not exists(...) 

Cependant, cela vient avec un problème. Un utilisateur peut à tout moment supprimer quelque chose de la TableB, donc si un utilisateur supprime une ligne et qu'un autre utilisateur arrive ou même que le même utilisateur arrive et fait quelque chose à la Table A, ma procédure stockée ramènera cette ligne supprimée dans le Tableau B. Comme il existera toujours dans la table A mais pas dans la table B et satisfera ainsi la condition de procédure stockée.

Alors, existe-t-il une meilleure façon de traiter deux tables qui doivent être mises à jour lors de l'utilisation d'encarts en bloc?

+1

Je suis à peu près sûr que tout le but de RDMS est d'éviter l'exclusion mutuelle et de mettre à jour les problèmes lors de plusieurs connexions simultanées.Je ne suis pas un expert de la DB, et je ne joue pas à la télévision, mais à ma connaissance, il existe des constructions que vous pouvez utiliser pour rendre la requête "atomique". –

+0

@San Jacinto: correct, mais SQLBulkCopy est une complication. Même alors, les écritures ultérieures ne peuvent pas distinguer les lignes qui sont les leurs, qui proviennent des écritures précédentes avec des espaces dans B. – gbn

Répondre

3

SqlBulkCopy complique ce donc j'envisager d'utiliser une table de mise en scène et une OUTPUT clause

exemple, dans un mélange de code pseudo-client et SQL

create SQLConnection 

Create #temptable 
Bulkcopy to #temptable 

Call proc on same SQLConnection 

proc: 
    INSERT tableA (..) 
    OUTPUT INSERTED.key, .. INTO TableB 
    SELECT .. FROM #temptable 

close connection 

Notes:

  • la tentation sera locale à la connexion et sera isolée

  • les écritures à A et B seront atomiques
  • chevauchement ou écrit plus tard ne se soucient pas de ce qui se passe plus tard à A et B
  • soulignant le dernier point, A et B ne seront peuplés que de l'ensemble des lignes dans #temptable

Alternative:

Ajouter une autre colonne à A et B appelé sessionid et l'utiliser pour identifier les lots de ligne.

1

Une option serait d'utiliser la clause de sortie de serveurs SQL:

INSERT YourTable (name) 
OUTPUT INSERTED.* 
VALUES ('NewName') 

Cela renverra l'id, name des lignes insérées au client, de sorte que vous pouvez les utiliser dans l'opération d'insertion pour la deuxième table.

+0

C'est pourquoi j'ai dit que SQLBulkCOpy complique cela: pas de clause OUTPUT ... – gbn

1

Juste comme une solution alternative, vous pouvez utiliser database triggers pour mettre à jour la deuxième table.

+0

Simple, mais vous auriez besoin de spécifier [ déclencheurs de feu] [http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopyoptions.aspx] qui pourrait avoir besoin de droits DDL – gbn