2010-05-31 9 views
16

J'utilise C# et utilise SqlBulkCopy. J'ai un problème cependant. J'ai besoin de faire un insert de masse dans une table puis un autre insert de masse dans une autre table.Possibilité de récupérer les ID PrimayKey après une BulkCopy SQL?

Ces 2 ont une relation PK/FK.

Table A 
Field1 -PK auto incrementing (easy to do SqlBulkCopy as straight forward) 

Table B 
Field1 -PK/FK - This field makes the relationship and is also the PK of this table. It is not auto incrementing and needs to have the same id as to the row in Table A. 

Ainsi, ces tables ont une relation un à un mais je ne suis pas sûr comment récupérer tous les PK Id que l'insert de masse fait puisque je les ai besoin pour le tableau B.

Modifier

Puis-je faire quelque chose comme ça?

SELECT * 
FROM Product 
WHERE NOT EXISTS (SELECT * FROM ProductReview WHERE Product.ProductId = ProductReview.ProductId AND Product.Qty = NULL AND Product.ProductName != 'Ipad') 

Cela devrait trouver toutes les lignes où la vient d'être inséré copie en bloc sql. Je ne suis pas sûr de savoir comment prendre les résultats de cela, puis faire un insert de masse avec eux d'un SP. Le seul problème que je peux voir avec ceci est que si un utilisateur fait les enregistrements un à la fois et une cette commande s'exécute en même temps il pourrait essayer d'insérer une rangée deux fois dans la "table de revue de produit". Donc, disons que j'ai eu comme un utilisateur utilisant la manière manuelle et un autre utilisateur faisant la masse à peu près au même moment.

manière manuelle. 1. L'utilisateur soumet des données 2. Linq to sql L'objet produit est créé et rempli avec les données et envoyé. 3. cet objet contient maintenant le ProductId 4. Un autre objet linq to sql est créé pour la table de revue de produit et est inséré (l'identifiant de produit de l'étape 3 est envoyé).

Chemin de masse. 1. L'utilisateur saisit les données d'un utilisateur partageant les données. 2. Toutes les lignes Product de l'utilisateur de partage sont saisies. 3. L'insertion de copie SQL en bloc sur les lignes de produits a lieu. 4. Mon SP sélectionne toutes les lignes qui existent uniquement dans la table Produit et qui remplissent d'autres conditions. 5. L'insertion de masse se produit avec ces lignes. Donc, que se passe-t-il si l'étape 3 (façon manuelle) se produit en même temps que l'étape 4 (chemin de masse). Je pense qu'il essayerait d'insérer deux fois la même ligne provoquant une contrainte primaire d'exécution.

+0

Qu'est-ce qui lie les tables en coup droit? –

Répondre

12

Dans ce scénario, je voudrais utiliser SqlBulkCopy à insérer dans une table de mise en scène (c.-à-un qui ressemble à les données que je veux importer, mais ne fait pas partie des principales tables transactionnelles), puis à la DB à INSERT/SELECT pour déplacer les données dans la première table réelle. Maintenant, j'ai deux choix en fonction de la version du serveur; Je pourrais faire une seconde INSERT/SELECT à la deuxième table réelle, ou je pourrais utiliser la clause INSERT/OUTPUT pour faire la deuxième insertion, en utilisant les lignes d'identité de la table.

Par exemple:

 -- dummy schema 
    CREATE TABLE TMP (data varchar(max)) 
    CREATE TABLE [Table1] (id int not null identity(1,1), data varchar(max)) 
    CREATE TABLE [Table2] (id int not null identity(1,1), id1 int not null, data varchar(max)) 

    -- imagine this is the SqlBulkCopy 
    INSERT TMP VALUES('abc') 
    INSERT TMP VALUES('def') 
    INSERT TMP VALUES('ghi') 

    -- now push into the real tables 
    INSERT [Table1] 
    OUTPUT INSERTED.id, INSERTED.data INTO [Table2](id1,data) 
    SELECT data FROM TMP 
+0

Hmm. Je travaillais sur quelque chose que vous pensez que cela fonctionnerait (voir mon édition). Sinon, je suppose que je vais essayer une table de mise en scène. – chobo2

+2

@ chobo2 - bien, sauf dans quelques cas, j'utiliserais une table de transit de toute façon - pour que: Je n'affecte pas la vraie table pendant le temps d'E/S du réseau, et b: pour obtenir des journaux de transaction complets. –

+0

Ok, je viens de recevoir mon montage. En passant je pense que je pourrais avoir à faire une mise en scène tbl. Pas encore sûr. J'ai quelques questions sur votre chemin si. Est-ce que - Est-ce que ces tables factices sont créées sur le fichier ou simplement utilisées à titre d'exemple? 2ème comment faites-vous un SQlbulkCopy dans une procédure stockée. 3ème comment fonctionne cette chose de poussée. Vous venez d'insérer la table entière ou quelque chose? 4e sur les connexions simultanées où peut-être quelques utilisateurs? Tout irait dans la table de mise en scène, il devrait donc y avoir un moyen de savoir quelles données ajouter, puis supprimer? – chobo2

0

En fonction de vos besoins et de contrôle que vous avez des tables, vous pouvez envisager d'utiliser UNIQUEIDENTIFIERs (GUID) au lieu de vos clés primaires IDENTITY. Cela déplace la gestion des clés hors de la base de données et dans votre application. Il y a des compromis sérieux à cette approche, donc cela peut ne pas répondre à vos besoins. Mais cela peut valoir la peine d'être considéré. Si vous savez à coup sûr que vous allez injecter beaucoup de données dans vos tables via bulk-insert, il est souvent très pratique d'avoir ces clés gérées dans votre modèle d'objet plutôt que votre application s'appuyant sur la base de données pour vous redonner Les données.

Vous pouvez également adopter une approche hybride avec des tables de transfert, comme indiqué précédemment. Obtenez les données dans ces tables en utilisant des GUID pour les relations, puis, via des instructions SQL, vous pouvez obtenir les clés étrangères entières dans l'ordre et pomper des données dans vos tables de production.

5

Si votre application le permet, vous pouvez ajouter une autre colonne dans laquelle vous stockez un identifiant de l'insert en vrac (un guid par exemple). Vous devez définir cet identifiant explicitement.

Ensuite, après l'insertion en bloc, il vous suffit de sélectionner les lignes qui ont cet identificateur.

+0

I pense que c'est la seule façon d'être toujours sûr de ce que vous avez inséré +1 – Dizzle

1

J'ai eu le même problème où j'ai dû récupérer les identifiants des lignes insérées avec SqlBulkCopy. Ma colonne d'ID était une colonne d'identité.

Solution:

J'ai inséré 500+ lignes avec copie en bloc, puis les sélectionnés de retour avec la requête suivante:

SELECT TOP InsertedRowCount * 
FROM MyTable 
ORDER BY ID DESC 

Cette requête renvoie les lignes que je viens insérer leur ids. Dans mon cas, j'avais une autre colonne unique. J'ai donc choisi cette colonne et mon ID. Puis les mappés avec un IDictionary comme ça:

IDictionary<string, int> mymap = new Dictionary<string, int>() 
mymap[Name] = ID 

Espérons que cela aide.

+9

Ceci est une bonne solution, mais ** SEULEMENT ** si vous pouvez ** garantir ** qu'aucun enregistrement n'est inséré depuis un autre thread après l'insertion mais avant de sélectionner les éléments. – Nuzzolilo

0

Je voudrais:

  1. Allumez l'identité insérer sur la table

  2. Prenez l'identifiant de la dernière ligne de la table

  3. boucle de (int i = Id; i < datable.rows.count+1; i++)

  4. En la boucle, affectez la propriété Id de votre datable à i+1.

  5. Exécutez votre insertion SQL en vrac avec votre identité Keep activée.

  6. identité Mettez reinsére hors

Je pense que c'est le moyen le plus sûr d'obtenir votre ids sur un insert en vrac SQL car il empêchera ids dépareillées qui pourraient causés par l'application est exécutée sur un autre thread.

0

Responsabilité: Je suis le propriétaire du projet C# Bulk Operations

La bibliothèque surmonter les limites SqlBulkCopy et ajouter des fonctionnalités flexibles comme valeur d'identité insérée de sortie. Derrière le code, il fait exactement comme la réponse acceptée mais beaucoup plus facile à utiliser.

var bulk = new BulkOperation(connection); 

// Output Identity 
bulk.ColumnMappings.Add("ProductID", ColumnMappingDirectionType.Output); 
// ... Column Mappings... 

bulk.BulkInsert(dt); 
+4

Je blesse, comment les gens peuvent-ils commercialiser leurs produits sur ce forum. :-) Les fonctionnalités liées à SklBulkCopy sont simplement emballées pour un coût ... Incroyable. – Usman

Questions connexes