2010-05-31 7 views
16

Ich benutze C# und mit SqlBulkCopy. Ich habe jedoch ein Problem. Ich muss eine Masseneingabe in eine Tabelle und dann eine weitere Masseneingabe in eine andere Tabelle vornehmen.Möglich, PrimayKey IDs nach einer SQL BulkCopy zurück zu bekommen?

Diese 2 haben eine PK/FK-Beziehung.

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. 

Also diese Tabellen haben eine Eins-zu Eins-Beziehung, aber ich bin nicht sicher, wie alle jene PK Id zurück zu bekommen, dass der Masseneinsatz gemacht, da ich sie brauche für Tabelle B

bearbeiten

Konnte ich so etwas tun?

Dies sollte alle Zeilen finden, die nur mit der sql Bulk-Kopie eingefügt wurden. Ich bin mir nicht sicher, wie ich die Ergebnisse daraus nehmen soll, dann mache eine Masse mit ihnen aus einem SP.

Das einzige Problem, das ich damit sehen kann, ist, dass, wenn ein Benutzer die Datensätze nacheinander tut und eine This-Anweisung zur gleichen Zeit ausgeführt wird, könnte es versuchen, eine Zeile zweimal in die "Product Review Table" einzufügen.

Also sagen, ich habe wie ein Benutzer den manuellen Weg und einen anderen Benutzer die Masse Weg etwa zur gleichen Zeit.

manuellen Weg. 1. Benutzer sendet Daten 2. Linq zu sql Produktobjekt wird gemacht und mit den Daten gefüllt und eingereicht. 3. Dieses Objekt enthält jetzt die ProductId 4. Ein weiteres linq to sql-Objekt wird für die Produktübersichtstabelle erstellt und eingefügt (Produkt-ID aus Schritt 3 wird mitgeschickt).

Massenweg. 1. Der Benutzer erfasst Daten von einem Benutzer, der die Daten teilt. 2. Alle Produktreihen vom Sharing-Benutzer werden erfasst. 3. SQL Bulk-Kopie einfügen auf Produktreihen geschieht. 4. Mein SP wählt alle Zeilen aus, die nur in der Produkttabelle vorhanden sind und erfüllt einige andere Bedingungen 5. Masseneinfügung geschieht mit diesen Zeilen.

Was passiert also, wenn Schritt 3 (manueller Weg) gleichzeitig mit Schritt 4 (Massenweg) passiert? Ich denke, es würde versuchen, die gleiche Zeile zweimal einzufügen, was zu einer Ausnahme für die primäre Einschränkung führt.

+0

Was bindet die Tabellen im Voraus? –

Antwort

12

In diesem Szenario würde ich SqlBulkCopy verwenden, um in eine Staging Tabelle einzufügen (dh eine, die wie die Daten, die ich importieren mag aussieht, ist aber Teil der wichtigsten Transaktionstabellen nicht) und dann bei der DB zu einem INSERT/SELECT, um die Daten in die erste reelle Tabelle zu verschieben.

Jetzt habe ich zwei Möglichkeiten je nach Server-Version; Ich könnte eine zweite INSERT/SELECT auf die zweite reale Tabelle tun, oder ich könnte die INSERT/OUTPUT -Klausel verwenden, um die zweite Einfügung zu tun, die Identität Reihen von der Tabelle verwendend.

Zum Beispiel:

 -- 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. Ich habe an etwas gearbeitet, glaubst du, dass es funktionieren würde (siehe meine Bearbeitung). Wenn nicht, werde ich einen Staging-Tisch versuchen. – chobo2

+2

@ chobo2 - Nun, außer in ein paar Szenarien würde ich sowieso eine Zwischenspeichertabelle verwenden - damit a: Ich habe keinen Einfluss auf die reale Tabelle während der Netzwerk-IO-Zeit, und b: um volle Transaktionsprotokolle zu erhalten. –

+0

Ok, ich habe gerade meine Bearbeitung fertiggestellt. Wenn ich durchgehe, denke ich, dass ich vielleicht eine Inszenierung machen muss. Noch nicht sicher. Ich habe jedoch einige Fragen auf dem Weg. Ist die - Sind diese Dummy-Tabelle auf der Datei erstellt oder nur zu Beispielzwecken verwendet? 2. Wie machst du eine SQlbulkCopy in einer gespeicherten Prozedur. 3. Wie funktioniert diese Push-Sache? Sie fügen nur die gesamte Tabelle oder etwas ein? 4. Wie wäre es mit gleichzeitigen Verbindungen wo vielleicht ein paar Benutzer? Es würde alles in die Staging-Tabelle gehen, also müsste es eine Art geben, um zu wissen, welche Daten hinzugefügt und dann gelöscht werden sollen. – chobo2

0

Je nach Bedarf und wie viel Kontrolle Sie der Tabellen haben, möchten Sie vielleicht mit UNIQUEIDENTIFIERs (Guids) statt Ihrer Identität Primärschlüssel zu berücksichtigen. Dadurch wird die Schlüsselverwaltung außerhalb der Datenbank und in Ihre Anwendung verschoben. Es gibt einige ernsthafte Kompromisse zu diesem Ansatz, so dass es möglicherweise nicht Ihren Anforderungen entspricht. Aber es könnte eine Überlegung wert sein. Wenn Sie sicher sind, dass Sie eine Menge Daten über Bulk-Insert in Ihre Tabellen pumpen, ist es oft sehr praktisch, diese Schlüssel in Ihrem Objektmodell verwalten zu lassen, anstatt dass Ihre Anwendung sich auf die Datenbank verlässt, um Ihnen die Daten zurückzugeben Daten.

Sie könnten auch einen Hybridansatz mit Staging-Tabellen verwenden, wie zuvor vorgeschlagen. Holen Sie die Daten in diese Tabellen, indem Sie GUIDs für die Beziehungen verwenden, und dann können Sie mithilfe von SQL-Anweisungen die ganzzahligen Fremdschlüssel in der richtigen Reihenfolge abrufen und Daten in Ihre Produktionstabellen pumpen.

5

Wenn Ihre App dies zulässt, können Sie eine weitere Spalte hinzufügen, in der Sie eine Kennung der Masseneinfügung (z. B. eine GUID) speichern. Sie würden diese ID explizit festlegen.

Dann nach der Massen einfügen, wählen Sie nur die Zeilen, die diese Kennung haben.

+0

I Denken Sie daran, dass Sie immer sicher sein können, was Sie eingefügt haben. +1 – Dizzle

1

Ich hatte das gleiche Problem, wo ich zurück Ids der Zeilen mit SqlBulkCopy eingefügt bekommen musste. Meine ID-Spalte war eine Identitätsspalte.

Lösung:

I 500+ Reihen mit Bulk-Kopie eingefügt haben, und ausgewählt sie dann mit der folgenden Abfrage zurück:

SELECT TOP InsertedRowCount * 
FROM MyTable 
ORDER BY ID DESC 

Diese Abfrage, die Zeilen zurückgibt ich mit gerade eingefügt haben ihre IDs. In meinem Fall hatte ich eine andere einzigartige Spalte. Also habe ich diese Spalte und ID ausgewählt. Dann abgebildet sie mit einem IDictionary etwa so:

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

Hoffnung, das hilft.

+9

Dies ist eine gute Lösung, aber ** NUR **, wenn Sie ** garantieren ** können, dass nach dem Einfügen keine Datensätze aus einem anderen Thread eingefügt werden aber bevor Sie die Elemente auswählen. – Nuzzolilo

0

Ich würde:

  1. Schalten Sie Identität einfügen auf dem Tisch

  2. greifen die Id der letzten Zeile der Tabelle

  3. Schleife von (int i = Id; i < datable.rows.count+1; i++)

  4. In die Schleife, weisen Sie die ID-Eigenschaft Ihres Datenspeichers i+1 zu.

  5. Führen Sie Ihre SQL-Masseneinfügung mit Ihrer behalten Identität ausgeführt.

  6. Schalten Identität aus

einfügen zurück denke ich, das ist der sicherste Weg, um Ihre IDs auf einer SQL-Masseneinfügung zu bekommen, weil sie nicht übereinstimmen ids verhindern wird, dass durch die Anwendung verursacht könnte auf einem anderen Thread ausgeführt werden.

0

Haftungsausschluss: Ich bin der Besitzer des Projekts C# Bulk Operations

Die Bibliothek SqlBulkCopy Einschränkungen zu überwinden und flexible Funktionen wie Ausgabe eingefügt Identitätswert hinzuzufügen.

Hinter dem Code, es tut genau wie die angenommene Antwort, aber viel einfacher zu bedienen.

var bulk = new BulkOperation(connection); 

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

bulk.BulkInsert(dt); 
+4

Ich wundere mich, wie Leute ihre Produkte auf diesem Forum vermarkten können. :-) SklBulkCopy verwandte Funktionen sind nur für so viel Kosten verpackt ... Incredible. – Usman

Verwandte Themen