Dapper, как вставить несколько строк с одним и тем же внешним ключом

У меня есть дочерняя таблица, которая ссылается на родительскую таблицу с отношением 1 ко многим. ПК -> несколько внешних ключей. Причина в том, что таблица FK представляет собой список объектов, связанных с идентификатором в родительской таблице.

Как я могу использовать dapper для вставки нескольких строк с одним и тем же FK?

assessmentModel.locationInformationModels = new List<LocationInformationModel>();

string sqlStatement = @"INSERT INTO LocationInformation
                                ([LocationInformationId]                          
                                ,[Address1]
                                ,[Address2]
                                ,[City]
                                ,[State]
                                ,[Zip])
                                VALUES(
                                @LocationInformationId,@Address1,@Address2,@City,@State,@Zip)";            
         
using (var connection = new SqlConnection(_connectionString))
            {
                await connection.OpenAsync();
                using (var ts = connection.BeginTransaction())
                {
                    var retVal = await connection.ExecuteAsync(sqlStatement, assessmentModel.locationInformationModels, transaction:ts);
                    ts.Commit();
                    return retVal;
                }        
            }

Итак, если у меня есть 1000 строк. Я вызываю базу данных 1000 раз? Это бессмысленно

CodeMan03 19.02.2023 06:25

Кажется, я неправильно понял вопрос :o) - Можете ли вы добавить дополнительную информацию о структуре таблицы, где мы можем видеть PK и FK, и о дизайне двух связанных классов, где мы также видим PK и FK, которые вы хотите использовать.

Sir Rufo 19.02.2023 08:51

Есть решение с Dapper-Plus dapper-plus.net/…

Sir Rufo 19.02.2023 09:09

@SirRufo Это стоит денег

CodeMan03 21.02.2023 23:23

Вы про Dapper-Plus или "добавьте еще немного информации"?

Sir Rufo 22.02.2023 06:44

@SirRufo "Dapper"-Plus не имеет ничего общего с Dapper. Кто-то похитил имя и отравил поисковые индексы, чтобы вместо настоящего Dapper отображались их ошибочные недокументированные продукты и продукты с закрытым исходным кодом. У создателей Dapper есть очень сильные мысли по этому поводу, начиная с At least fix the doc errors!.

Panagiotis Kanavos 22.02.2023 09:58

@ CodeMan03, в чем собственно вопрос? Как получить значение LocationInformation.Id? connection.ExecuteAsync(...,locationInformationModels) уже вставляет каждый элемент по одному. Dapper не будет переписывать ваш SQL-запрос, чтобы он принимал несколько строк. Если вы хотите получить идентификатор, вам нужно использовать предложение OUTPUT и использовать QueryAsync вместо ExecuteAsync

Panagiotis Kanavos 22.02.2023 10:09
Конечные и Readonly классы в PHP
Конечные и Readonly классы в PHP
В прошлом, когда вы не хотели, чтобы другие классы расширяли определенный класс, вы могли пометить его как final.
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
Если вы уже умеете работать с React, создание мобильных приложений для iOS и Android - это новое приключение, в котором вы сможете применить свои...
БЭМ: Конвенция об именовании CSS
БЭМ: Конвенция об именовании CSS
Я часто вижу беспорядочный код CSS, особенно если проект большой. Кроме того, я совершал эту ошибку в профессиональных или личных проектах и...
Революционная веб-разработка ServiceNow
Революционная веб-разработка ServiceNow
В быстро развивающемся мире веб-разработки ServiceNow для достижения успеха крайне важно оставаться на вершине последних тенденций и технологий. По...
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Заголовок веб-страницы играет наиболее важную роль в SEO, он помогает поисковой системе понять, о чем ваш сайт.
Конфигурация Jest в angular
Конфигурация Jest в angular
В этой статье я рассказываю обо всех необходимых шагах, которые нужно выполнить при настройке jest в angular.
1
7
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если я правильно вас понял, вы хотите делать вставки в таблицу партиями. Pure Dapper не имеет встроенного способа выполнения массовых вставок, поэтому вы можете либо использовать Dapper-Plus, либо SqlBulkCopy для всех массовых действий, которые вы хотите выполнить.

С помощью SqlBulkCopy вы можете настроить динамическое сопоставление столбцов с использованием отражения, чтобы избежать явного определения всех столбцов.

Вот один из способов настроить SqlBulkCopy, который можно модифицировать для вставки вместо удаления.
FinneVirta 22.02.2023 09:57
Ответ принят как подходящий

Вопрос немного не ясен. Код показывает вставку списка элементов без чего-либо похожего на внешний ключ. В любом случае, Dapper — это микроORM, он не обрабатывает отношения между сущностями или ключи автообновления. Он также не изменит предоставленный оператор SQL для обработки нескольких объектов.

Я подозреваю, что реальный вопрос заключается в том, как вернуть сгенерированное значение из базы данных, например, ключ IDENTITY, хотя код показывает, что LocationInformationId предоставляется приложением. Для этого запрос нужно будет изменить, чтобы он возвращал любое сгенерированное значение, например, с предложением OUTPUT.

Возврат сгенерированных значений

Например, это вернет автоматически сгенерированный идентификатор:

var sql = """
    INSERT INTO LocationInformation
        ([Address1]
        ,[Address2]
        ,[City]
        ,[State]
        ,[Zip])
    OUTPUT inserted.LocationInformationId
    VALUES(@Address1,@Address2,@City,@State,@Zip)
    """;

Код вопроса уже использует ExecuteAsync(sql, IEnumerable<T>,...) для вставки нескольких элементов. Это выполняет запрос один раз для каждого элемента, но не возвращает никаких результатов. Для QueryAsync нет эквивалента, поэтому приложению придется выполнять INSERT явно:

foreach(var item in items)
{
    var newId=await connection.QueryAsync(sql,item);
    item.Id=newId;
}

Конструкторы строк

Можно вставить несколько строк с помощью одного INSERT с помощью конструкторов строк, но для этого требуется динамическое создание SQL-запроса:

    INSERT INTO LocationInformation
        ([Address1]
        ,[Address2]
        ,[City]
        ,[State]
        ,[Zip])
    VALUES
    OUTPUT inserted.LocationInformationId
    (@Address1_01,@Address2_01,@City_01,@State_01,@Zip_01),
    (@Address1_02,@Address2_02,@City_02,@State_02,@Zip_02),
    (@Address1_03,@Address2_03,@City_03,@State_03,@Zip_03),
    ...

Все значения элементов также должны быть сведены приложением к списку параметров. Не очень полезно.

Табличные параметры

Другой вариант — использовать параметр с табличным значением для одновременной вставки нескольких значений, переданных как DataTable. Это требует создания табличного типа параметра в базе данных и преобразования данных в DataTable, например:

CREATE TYPE dbo.LocationTableType AS TABLE  
    ( Address1 nvarchar(50), ...  ) 

Запрос должен измениться на INSERT ... SELECT с использованием параметра таблицы:

var sql = """
    INSERT INTO LocationInformation
        ([Address1]
        ,[Address2]
        ,[City]
        ,[State]
        ,[Zip])
    OUTPUT inserted.LocationInformationId
    SELECT Address1,Address2,City,State,Zip 
    FROM @table
    """;

ToDataTable от MoreLinq можно использовать для преобразования входных элементов в DataTable. После этого вызов QueryAsync выполнит INSERT и вернет список выходов:

var table=items.ToDataTable();
var newIds=await connection.QueryAsync(sql,table);

Другие вопросы по теме