2010-05-31 8 views
16

Używam C# i przy użyciu SqlBulkCopy. Mam jednak problem. Muszę zrobić masową wkładkę do jednego stołu, a następnie kolejną masową wkładkę do innego stołu.Możliwość odzyskania identyfikatorów PrimayKey po SQL BulkCopy?

Te 2 mają związek 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. 

Więc te tabele mają jeden do jednego związku, ale jestem pewien, jak wrócić Wszystkie te PK Id że masa wkładka wykonana ponieważ muszę je Tabela B.

Edit

Czy mogę zrobić coś takiego?

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

Powinny znaleźć wszystkie wiersze, które właśnie zostały wstawione przy użyciu kopii zbiorczej sql. Nie jestem pewien, jak wziąć z tego wyniki, a następnie zrób z nich masową wkładkę z SP.

Jedyny problem jaki widzę z tym, to że jeśli użytkownik wykonuje te zapisy pojedynczo, a instrukcja ta działa w tym samym czasie, może spróbować wstawić wiersz dwa razy do "Tabeli przeglądu produktów".

Powiedzmy, że mam jednego użytkownika korzystającego z trybu ręcznego, a inny użytkownik robi masę mniej więcej w tym samym czasie.

sposób ręczny. 1. Użytkownik przesyła dane 2. Linq do sql Obiekt produktu jest tworzony i wypełniany danymi oraz przesyłany. 3. ten obiekt zawiera teraz ProductId 4. Kolejny obiekt linq to sql jest tworzony dla tabeli recenzji produktu i jest wstawiany (identyfikator produktu z kroku 3 jest wysyłany razem).

Droga masowa. 1. Użytkownik pobiera dane od użytkownika udostępniającego dane. 2. Wszystkie wiersze produktu od użytkownika udostępniania są chwytane. 3. Wstawianie kopii zbiorczej SQL w wierszach produktów. 4. Mój SP wybiera wszystkie wiersze, które istnieją tylko w tabeli produktów i spełnia inne warunki. 5. Wstawianie masy odbywa się z tymi wierszami.

Co się dzieje, gdy krok 3 (droga ręczna) ma miejsce w tym samym czasie co krok 4 (droga masowa). Myślę, że spróbuje wstawić dwa razy ten sam wiersz, co spowoduje wykonanie ograniczenia podstawowego.

+0

Co wiąże tabele na forherze? –

Odpowiedz

12

W tym scenariuszu, użyłbym SqlBulkCopy wstawić do pomostowym tabeli (czyli taki, który wygląda jak dane Chcę importować, ale nie jest częścią głównych tabel transakcyjnych), a następnie w DB do INSERT/SELECT, aby przenieść dane do pierwszej prawdziwej tabeli.

Teraz mam dwie możliwości w zależności od wersji serwera; Mógłbym zrobić sekundę INSERT/SELECT do drugiej prawdziwej tabeli lub mógłbym użyć klauzuli INSERT/OUTPUT do wykonania drugiej wstawki, używając wierszy tożsamości z tabeli.

Na przykład:

 -- 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. Pracowałem nad czymś, co według Ciebie mogłoby zadziałać (zobacz moją edycję). Jeśli nie, to sądzę, że spróbuję stendażu. – chobo2

+2

@ chobo2 - cóż, z wyjątkiem kilku scenariuszy, w każdym razie korzystałbym z tabeli pomostowej - tak, że: nie mam wpływu na rzeczywisty stół podczas czasu IO sieci, oraz b: aby uzyskać pełne dzienniki transakcji. –

+0

Ok Właśnie dostałem moją edycję. Przechodząc przez myślę, że być może będę musiał zrobić tbl sposób inscenizacji. Nie wiem jeszcze. Mam jednak kilka pytań po drodze. Czy są to - czy te fałszywe tabele są tworzone w pliku, czy tylko wykorzystywane do celów przykładowych? 2. Jak zrobić SQlbulkCopy w procedurze przechowywanej. 3. Jak działa ta funkcja push. Po prostu wstawiasz cały stół czy coś? 4. co powiesz na współbieżne połączenia, w których może być kilku użytkowników? Wszystko pójdzie do stołu inscenizacji, więc trzeba będzie jakiś sposób dowiedzieć się, które dane dodać, a następnie usunąć? – chobo2

0

W zależności od potrzeb i ile kontroli trzeba tabel, można rozważyć użycie UNIQUEIDENTIFIERs (GUID) zamiast kluczy pierwotnych tożsamość. Przenosi to zarządzanie kluczami poza bazę danych i do aplikacji. Jest kilka poważnych kompromisów w tym podejściu, więc może nie spełnić twoich potrzeb. Ale może być warte rozważenia. Jeśli wiesz na pewno, że będziesz pompował wiele danych do tabel za pomocą opcji bulk-insert, często jest bardzo przydatne, aby te klucze były zarządzane w modelu obiektu, a nie w aplikacji bazującej na bazie danych, aby zwrócić dane.

Można również zastosować metodę hybrydową z tabelami pomostowymi, zgodnie z sugestiami. Pobierz dane do tych tabel za pomocą identyfikatorów GUID dla relacji, a następnie za pośrednictwem instrukcji SQL można uzyskać całkowitą klucze obce w kolejności i dane pompy do tabel produkcyjnych.

5

Jeśli aplikacja na to pozwala, możesz dodać kolejną kolumnę, w której będzie przechowywany identyfikator wkładu zbiorczego (np. Identyfikator). Powinieneś jawnie ustawić ten identyfikator.

Następnie po wstawieniu zbiorczym wystarczy wybrać wiersze, które mają ten identyfikator.

+0

I Myślę, że to jedyny sposób, abyś zawsze był pewien, co wstawiłeś +1 – Dizzle

1

Miałem ten sam problem, gdy musiałem odzyskać identyfikatory wierszy wstawionych z SqlBulkCopy. Moja kolumna ID była kolumną tożsamości.

Rozwiązanie:

mam wstawiony ponad 500 wierszy z kopii luzem, a następnie wybiera się je z następującym zapytaniem:

SELECT TOP InsertedRowCount * 
FROM MyTable 
ORDER BY ID DESC 

Ta kwerenda zwraca wierszy właśnie wstawione z ich ids. W moim przypadku miałem inną unikalną kolumnę. Wybrałem tę kolumnę i identyfikator. Następnie zmapowano je za pomocą takiego identyfikatora:

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

Mam nadzieję, że to pomoże.

+9

To jest dobre rozwiązanie, ale ** TYLKO ** jeśli możesz ** zagwarantować **, że żadne rekordy nie są wstawiane z innego wątku po wstawieniu ale zanim wybierzesz elementy. – Nuzzolilo

0

bym:

  1. Włącz tożsamości wstawić na stole

  2. Grab identyfikator ostatnim wierszu tabeli

  3. Loop z (int i = Id; i < datable.rows.count+1; i++)

  4. W w pętli, przypisz właściwość Id swojej bazy danych do i+1.

  5. Uruchom swoją masową wstawkę SQL z włączoną tożsamością.

  6. Turn tożsamość wstawić wycofać

myślę, że to najbezpieczniejszy sposób, aby uzyskać identyfikatory na wkładce SQL luzem, ponieważ będzie ona zapobiec niedopasowane identyfikatory, które mogłyby spowodowanych przez stosowanie być wykonywane w innym wątku.

0

Zastrzeżone: Jestem właścicielem projektu C# Bulk Operations

biblioteki przezwyciężyć SqlBulkCopy ograniczenia i dodać elastyczne funkcje jak wyjściowego wstawiane wartości tożsamości.

Za kodem odpowiada dokładnie zaakceptowanej odpowiedzi, ale jest łatwiejszy w użyciu.

var bulk = new BulkOperation(connection); 

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

bulk.BulkInsert(dt); 
+4

Jestem ranny, jak ludzie mogą sprzedawać swoje produkty na tym forum :-) SklBulkCopy związane z funkcjami są po prostu pakowane za tak wiele kosztów ... Niewiarygodne. – Usman

Powiązane problemy