2010-03-02 12 views
5

Próbuję dowiedzieć się, czy możliwe jest wykonanie polecenia typu "wstaw do ... wybierz" z LINQ do SQL. Trochę LINQ do kodu SQL, który pozwoliłby mi wysłać jedno polecenie SQL do bazy danych, która wstawiłaby wiele wierszy do podanej tabeli.Wykonywanie INSERT INTO ... WYBIERZ z LINQ do SQL

Na przykład, jak sprawić, aby LINQ do SQL wysłał następującą instrukcję T-SQL do bazy danych SQL Server?

INSERT INTO Table1 
SELECT Table2.column1 + 1 AS column1, Table2.column2 + 2 AS column2 
WHERE Table2.column3 > 100 

Mógłbym oczywiście to osiągnąć za pomocą funkcji DataContext.ExecuteCommand ale to będzie realizowane natychmiast, bez skorzystania z automatycznej obsługi transakcji otrzymasz z DataContext.SubmitChanges. Oprócz tego mam serię aktualizacji i chciałbym, aby wszystkie zostały wycofane w przypadku błędu.

Wszelkie pomysły?

UPDATE: Tutaj jest rzeczywisty kod:

 var bs_prep = 
      from b in dc.T_EDR_FILEBODies 
      join 
      unpaid in dc.V_UNPAIDs 
      on 
       b.NUM_ADC.Substring(1, 9) equals unpaid.NOCONT 
      join 
      acordo in dc.T_ACORDOS_RECOM_APREs 
      on 
       Convert.ToInt32(b.NUM_ADC.Substring(1, 9)) equals acordo.ID_Contrato 
      where 
       b.ID_EDR == id_edr 
       && 
       (
        unpaid.NUM_INCUMPRIMENTOS <= max_unpaid_consec 
        && 
        unpaid.TOTAL_NUM_INCUPRIMENTOS <= max_unpaid_nonconsec 
       ) 
       || 
       (
        acordo.Activo == true 
        && 
        acordo.Data_Recomeco <= now 
       ) 
      select new 
       { 
        ID_EDR = id_edr_filt, 
        NUM_LINHA = b.NUM_LINHA, 
        CODREJ = b.CODREJ, 
        HDT = b.HDT, 
        IMPORT = b.IMPORT, 
        NIB_DEV = b.NIB_DEV, 
        NUM_ADC = b.NUM_ADC, 
        REF_DD_BC = b.REF_DD_BC, 
        REF_MOV = b.REF_MOV 
       } 
      ; 


     dc.T_EDR_FILEBODies.InsertAllOnSubmit(
      bs_prep.Select(
       b => new T_EDR_FILEBODY{ 
        CODREJ = b.CODREJ, 
        HDT = b.HDT, 
        ID_EDR = b.ID_EDR, 
        IMPORT = b.IMPORT, 
        NIB_DEV = b.NIB_DEV, 
        NUM_ADC = b.NUM_ADC, 
        NUM_LINHA = b.NUM_LINHA, 
        REF_DD_BC = b.REF_DD_BC, 
        REF_MOV = b.REF_MOV 
       } 
      ) 
     ); 

Szybkie wyjaśnienie: Podmiot T_EDR_FILEBODies mapuje do tabeli bazy danych, która w zasadzie przechowuje zawartość niektórych plików tekstowych importujemy. Jeden rekord odpowiada jednej linii w pliku tekstowym.

Próbuję utworzyć przefiltrowaną wersję zawartości pliku, kopiując rekordy z jednego pliku, nadając im nowy identyfikator pliku (ID_EDR=id_edr_filt), ale odfiltrowując niektóre linie. Jednostki LINQ do SQL to bezpośrednie odwzorowania do tabel bazy danych. Do tej pory nie dodałem żadnego kodu do mojego datacontextu. Mają klucze podstawowe, inaczej nie byłbym w stanie wstawiać na nich wstawek (czytałem gdzieś, że byłbym w stanie pozbyć się tego wyjątku, gdybym pozbył się kluczy podstawowych, ale jak widzisz, to nie byłoby działa w moim przypadku).

Kiedy uruchomić go otrzymuję następujący wyjątek rzucony przez InsertAllOnSubmit:

Explicit konstrukcja typu podmiotu T_EDR_FILEBODY 'w zapytaniu nie jest dozwolony.

Domyślam się, że rozumiem, że jednoznaczne skonstruowanie podmiotu w zapytaniu byłoby problematyczne. Jednostki zwracane przez zapytania mają śledzenie zmian, zmiany są tłumaczone na bazę danych po wywołaniu submarów. Ale jak można przetłumaczyć, w bazie danych, zmiany w jednostce utworzonej po stronie klienta? Ale czy to naprawdę oznacza, że ​​nigdy nie możesz wykonać polecenia typu INSERT INTO ... SELECT, używając LINQ do SQL?

+1

można zrobić „Korzystanie _tx jak Nowy TransactionScope()” i owinąć ExecuteCommand i cokolwiek innego w nim? – StingyJack

+0

Cóż, myślę, że mogę, i mogę być po prostu wybredny, ale trudno mi zaakceptować, że po prostu nie możesz wstawić do ... select statement using linq. Byłby to ogromny handycap. –

Odpowiedz

0

Można użyć

ctx.Table1.InsertAllOnSubmit(
    mySelectEnumeration.Select(x => new Table1DT { ... }) 
); 
  • InsertAllOnSubmit wstawia liczbę wpisów do LINQ do tabeli SQL.
  • mySelectEnumeration to zapytanie, które wybiera pozycje do wstawienia.
  • Select(new Table1DT { ... }) to transformacja wymagana do przekonwertowania typu danych wybranego zapytania na typ danych tabeli.

Można również użyć metody ExecuteCommand i zarządzać transakcją ręcznie.

using (var ctx = new DataClasses1DataContext()) { 
    ctx.Connection.Open(); 
    using (ctx.Transaction = ctx.Connection.BeginTransaction()) { 
     ctx.ExecuteCommand("sqlcommand"); 
     ctx.Transaction.Commit(); 
    } 
} 

lub przy wykorzystaniu zakresu transakcji:

using (var ctx = new DataClasses1DataContext()) { 
    using (var scope = new TransactionScope()) { 
     ctx.ExecuteCommand("sqlcommand"); 
     scope.Complete(); 
    } 
} 
+0

Nie jestem pewien, czy podjąłem twoją sugestię. Nie mogę zobaczyć, jak zainicjować instancję Table1DT na wbudowanym contructor na podstawie mySelectEnumeration. Jak mogę odwołać się do mySelectEnumeration? Alternatywnie próbowałem zamknąć 1. zapytanie (które zwraca IQueryable ) w innym zapytaniu za pomocą wbudowanego konstruktora Table1DT w klauzuli Select, a więc zwraca IQueryable . Ale pojawia się ten sam błąd, który powoduje wstawienie konstruktora wbudowanego w 1. kwerendę: Jawna konstrukcja typu jednostki "Tabela1DT" w zapytaniu jest niedozwolona. –

+1

Ponieważ nie znam twojej konkretnej klasy DataContext (ctx w mojej próbce), użyłem symboli zastępczych. 'Tabela1' jest symbolem zastępczym dla tabeli, do której należy wstawić elementy. 'mySelectEnumeration' jest wynikiem zapytania, które wykonujesz, aby wybrać elementy, które chcesz wstawić. 'Table1DT' jest typem danych twojego' Table1'. I "..." wskazuje, gdzie będziesz musiał ustawić właściwości "Table1", np. 'ID = x.identifier'. Nie mogę być bardziej konkretny bez znajomości twojego DataContext. – AxelEckenberger

+0

Ok mój błąd, myślę, że nie przeczytałem twojej odpowiedzi tak dokładnie, jak powinienem (przegapiłem "x =>"). OK próbował tego i nadal mam ten sam wyjątek w wywołaniu InsertAllOnSubmit: Jawna konstrukcja typu obiektu "Table1DT" w zapytaniu jest niedozwolona. (Używam tej samej notacji, której użyłeś). Czytałem o tym i wpadłem na pomysł, że z jakiegoś powodu nie można konstruować jednostek wewnątrz querys. Jednak nie rozumiem dlaczego. –

Powiązane problemy