2010-03-02 2 views
5

Я пытаюсь выяснить, возможно ли выполнить команду типа «insert into ... select» с LINQ to SQL. Немного кода LINQ to SQL, который позволит мне отправить одну SQL-команду в базу данных, которая будет вставлять несколько строк в заданную таблицу.Выполнение INSERT INTO ... SELECT с LINQ to SQL

Например, как заставить LINQ to SQL отправить следующую инструкцию T-SQL в базу данных SQL Server?

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

Я мог бы, конечно, добиться этого с помощью функции DataContext.ExecuteCommand, но это будет выполняться сразу же без воспользовавшись автоматической операции обработки вы получаете с DataContext.SubmitChanges. У меня есть ряд обновлений, кроме этого, и я бы хотел, чтобы все они откатились в случае ошибки.

Любые идеи?

UPDATE: Вот реальный код:

 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 
       } 
      ) 
     ); 

Краткое объяснение: T_EDR_FILEBODies объект отображает таблицу базы данных, которые в основном хранит содержимое некоторых текстовых файлов, которые мы импортируем. Одна запись соответствует одной строке в текстовом файле.

Что я пытаюсь сделать, это создать отфильтрованную версию содержимого файла, скопировав записи из одного файла, предоставив им новый идентификатор файла (ID_EDR=id_edr_filt), но отфильтровывая некоторые из строк. Объекты LINQ to SQL являются прямыми сопоставлениями таблиц базы данных. До сих пор я не добавил код в свой файл данных. У них есть первичные ключи, иначе я бы не смог сделать вставки на них (я где-то читал, что смог бы избавиться от этого исключения, если бы избавился от первичных ключей, но, как вы можете видеть, это не будет работа в моем случае).

Когда я запускаю его я получаю следующее исключение брошенного InsertAllOnSubmit:

Явного строительства типа объекта «T_EDR_FILEBODY» в запросе не допускаются.

Я думаю, я понимаю, что явное конструирование объекта внутри запроса было бы проблематичным. Объекты, возвращаемые запросами, имеют отслеживание изменений, изменения переводятся в базу данных при вызове подписок. Но как вы могли бы перевести в базу данных изменения на сущности, созданной на стороне клиента? Но действительно ли это означает, что вы никогда не сможете выполнять команду INSERT INTO ... SELECT с использованием LINQ to SQL?

+1

Вы можете сделать «Использование _tx в Нью-TransactionScope()» и оберните ExecuteCommand и все остальное в нем? – StingyJack

+0

Ну, я думаю, я могу, и я могу просто быть разборчивым, но мне трудно принять, что вы просто не можете вставлять в ... select заявление с помощью linq. Это был бы такой огромный handycap. – 2010-03-02 17:49:19

ответ

0

Вы можете использовать

ctx.Table1.InsertAllOnSubmit(
    mySelectEnumeration.Select(x => new Table1DT { ... }) 
); 
  • InsertAllOnSubmit вставляет число записей в Linq к таблице SQL.
  • mySelectEnumeration - это запрос, который выбирает элементы для вставки.
  • Select(new Table1DT { ... }) - это преобразование, необходимое для преобразования типа данных, выбранных вами в тип данных таблицы.

В качестве альтернативы вы можете использовать метод ExecuteCommand и управлять транзакцией вручную.

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

Или используя объем транзакций:

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

Я не уверен, что возьму ваше предложение. Я не могу понять, как инициализировать экземпляр Table1DT на встроенном конструкторе на основе mySelectEnumeration. Как я могу ссылаться на mySelectEnumeration? В качестве альтернативы я попытался инкапсулировать 1-й запрос (который возвращает IQueryable ) в другом запросе с встроенным конструктором Table1DT в предложении Select и поэтому возвращает IQueryable . Но я получаю ту же ошибку, я получаю встроенный конструктор в первом запросе: Явное построение типа сущности «Table1DT» в запросе недопустимо. – 2010-03-02 16:45:24

+1

Поскольку я не знаю вашего конкретного класса DataContext (ctx в моем примере), я использовал заполнители. 'Таблица1' является заполнителем таблицы в элементы должны быть вставлены. 'mySelectEnumeration' является результатом запроса, который вы делаете, чтобы выбрать элементы, которые вы хотите вставить. 'Table1DT' - это тип данных вашей' Table1'. И, '...' указывает, где вам нужно будет установить свойства «Table1», например. 'ID = x.identifier'. Я не могу быть более конкретным, не зная ваш DataContext. – AxelEckenberger

+0

Хорошо, моя ошибка, я думаю, я не читал ваш ответ так тщательно, как должен (я пропустил «x =>»). Ok попробовал это, и у меня все еще есть то же самое исключение в вызове InsertAllOnSubmit: Явное построение типа сущности «Table1DT» в запросе недопустимо. (Я использую то же обозначение, которое вы использовали). Я читал об этом, и у меня появилась идея, что по какой-то причине вы не можете создавать объекты внутри запросов. Однако не совсем понял почему. – 2010-03-02 17:38:04