Поиск…


параметры

параметр подробности
this cnn Основное соединение с базой данных - this метод расширения; соединение не должно быть открытым - если оно не открыто, оно автоматически открывается и закрывается.
<T> / Type (необязательно) Тип возвращаемого объекта; если неуниверсальный / не - Type используется API - , А dynamic объект возвращается на строку, имитируя свойство с именем для каждого имени столбца , возвращаемое из запроса (этот dynamic объект также реализует IDicionary<string,object> ).
sql SQL для выполнения
param (необязательно) Параметры для включения.
transaction (необязательно) Операция базы данных для связи с командой
buffered (необязательно) Предпочитаете ли вы предварительно использовать данные в списке (по умолчанию), а также открывать открытый IEnumerable над живым читателем
commandTimeout (необязательно) Тайм-аут для использования в команде; если не указано, предполагается SqlMapper.Settings.CommandTimeout (если указано)
commandType Тип выполняемой команды; по умолчанию - CommandText

замечания

Синтаксис для выражения параметров изменяется между СУБД. Все приведенные выше примеры используют синтаксис SQL Server, то есть @foo ; однако ?foo и :foo также должен работать нормально.

Базовый параметризованный SQL

Dapper позволяет легко следовать наилучшей практике с помощью полностью параметризованного SQL.

Бобби Столы

Параметры важны, поэтому dapper упрощает правильное использование. Вы просто выражаете свои параметры обычным способом для вашей РСУБД (обычно @foo ?foo или :foo ) и даете dapper объект, у которого есть член с именем foo . Самый распространенный способ сделать это - анонимный тип:

int id = 123;
string name = "abc";
connection.Execute("insert [KeyLookup](Id, Name) values(@id, @name)",
    new { id, name });

И это все. Dapper добавит требуемые параметры, и все должно работать.

Использование вашей объектной модели

Вы также можете использовать существующую объектную модель в качестве параметра:

KeyLookup lookup = ... // some existing instance
connection.Execute("insert [KeyLookup](Id, Name) values(@Id, @Name)", lookup);

Dapper использует командный текст для определения того, какие члены объекта добавить - обычно он не будет добавлять ненужные вещи, такие как Description , IsActive , CreationDate потому что команда, которую мы выпустили, явно не включает их, - хотя бывают случаи, когда может сделать это, например, если ваша команда содержит:

// TODO - removed for now; include the @Description in the insert

Он не пытается понять, что выше всего лишь комментарий.

Хранимые процедуры

Параметры хранимых процедур работают точно так же, за исключением того, что dapper не может попытаться определить, что следует / не следует включать - все доступные рассматриваются как параметр. По этой причине обычно предпочтительны анонимные типы:

connection.Execute("KeyLookupInsert", new { id, name },
    commandType: CommandType.StoredProcedure);

Ценностная инкрустация

Иногда удобство параметра (с точки зрения обслуживания и выразительности) может быть перевешивается его стоимостью в производительности, чтобы рассматривать его как параметр. Например, когда размер страницы фиксируется настройкой конфигурации. Или значение статуса соответствует значению enum . Рассматривать:

var orders = connection.Query<Order>(@"
select top (@count) * -- these brackets are an oddity of SQL Server
from Orders
where CustomerId = @customerId
and Status = @open", new { customerId, count = PageSize, open = OrderStatus.Open });

Единственным реальным параметром здесь является customerId - остальные два являются псевдопараметрами, которые фактически не изменятся. Часто РСУБД могут лучше работать, если обнаруживают их как константы. Для этого Dapper имеет специальный синтаксис - {=name} вместо @name - который применяется только к числовым типам. (Это минимизирует любую поверхность атаки из SQL-инъекции). Примером может служить следующее:

var orders = connection.Query<Order>(@"
select top {=count} *
from Orders
where CustomerId = @customerId
and Status = {=open}", new { customerId, count = PageSize, open = OrderStatus.Open });

Dapper заменяет значения литералами перед выпуском SQL, поэтому СУБД фактически видит что-то вроде:

select top 10 *
from Orders
where CustomerId = @customerId
and Status = 3

Это особенно полезно, когда RDBMS-системы не просто принимают более правильные решения, а открывают планы запросов, которые предотвращают фактические параметры. Например, если предикат столбца относится к параметру, тогда отфильтрованный индекс с определенными значениями в этих столбцах нельзя использовать. Это связано с тем, что следующий запрос может иметь параметр отдельно от одного из указанных значений.

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

Список расширений

Обычный сценарий в запросах базы данных - IN (...) где список создается во время выполнения. Для большинства РСУБД не хватает хорошей метафоры для этого - и для этого нет универсального решения для РСУБД . Вместо этого dapper обеспечивает нежное автоматическое расширение команд. Все, что требуется, - это заданное значение параметра, которое является IEnumerable . Команда, включающая @foo , расширена до (@foo0,@foo1,@foo2,@foo3) (для последовательности из 4 элементов). Наиболее распространенным применением этого является IN :

int[] orderIds = ...
var orders = connection.Query<Order>(@"
select *
from Orders
where Id in @orderIds", new { orderIds });

Затем автоматически расширяется, чтобы выдать соответствующий SQL для многорядной выборки:

select *
from Orders
where Id in (@orderIds0, @orderIds1, @orderIds2, @orderIds3)

с параметрами @orderIds0 т. д. добавляются как значения, взятые из атрибута. Обратите внимание, что тот факт, что он недействителен SQL первоначально, является преднамеренным, чтобы гарантировать, что эта функция не используется ошибочно. Эта функция также корректно работает с подсказкой OPTIMIZE FOR / UNKNOWN в SQL Server; если вы используете:

option (optimize for
    (@orderIds unknown))

он правильно расширит это:

option (optimize for
    (@orderIds0 unknown, @orderIds1 unknown, @orderIds2 unknown, @orderIds3 unknown))

Выполнение операций с несколькими наборами входов

Иногда вы хотите сделать одно и то же несколько раз. Dapper поддерживает это в методе Execute если внешний параметр (который обычно представляет собой один анонимный тип или экземпляр модели домена) фактически предоставляется как последовательность IEnumerable . Например:

Order[] orders = ...
// update the totals
connection.Execute("update Orders set Total=@Total where Id=@Id", orders);

Здесь dapper просто делает простой цикл для наших данных, в основном так же, как если бы мы это сделали:

Order[] orders = ...
// update the totals
foreach(Order order in orders) {
    connection.Execute("update Orders set Total=@Total where Id=@Id", order);
}

Это использование становится особенно интересным в сочетании с async API в соединении, которое явно сконфигурировано для всех «Множественных наборов активных результатов» - в этом использовании dapper автоматически контактирует с операциями, поэтому вы не оплачиваете затраты на задержку в строке. Это требует немного более сложного использования,

await connection.ExecuteAsync(
    new CommandDefinition(
        "update Orders set Total=@Total where Id=@Id", 
         orders, flags: CommandFlags.Pipelined))

Обратите внимание, однако, что вы также можете изучить параметры таблицы.

Псевдопозиционные параметры (для поставщиков, которые не поддерживают именованные параметры)

Некоторые поставщики ADO.NET (в первую очередь: OleDB) не поддерживают именованные параметры; параметры вместо этого задаются только положением , с ? место-держатель. Dapper не знал бы, какой член использовать для них, поэтому dapper допускает альтернативный синтаксис ?foo? ; это будет то же самое, что @foo или :foo в других вариантах SQL, за исключением того, что dapper полностью заменит токен параметра ? перед выполнением запроса.

Это работает в сочетании с другими функциями, такими как расширение списка, поэтому справедливо следующее:

string region = "North";
int[] users = ...
var docs = conn.Query<Document>(@"
     select * from Documents
     where Region = ?region?
     and OwnerId in ?users?", new { region, users }).AsList();

.region .users члены .region и .users , а выданный SQL (например, у 3 пользователей):

     select * from Documents
     where Region = ?
     and OwnerId in (?,?,?)

Обратите внимание, однако, что dapper не позволяет использовать один и тот же параметр несколько раз при использовании этой функции; это необходимо для того, чтобы несколько раз добавить одно и то же значение параметра (которое может быть большим). Если вам нужно ссылаться на одно и то же значение несколько раз, рассмотрите объявление переменной, например:

declare @id int = ?id?; // now we can use @id multiple times in the SQL

Если переменные недоступны, вы можете использовать двойные имена членов в параметрах - это также сделает очевидным, что значение отправляется несколько раз:

int id = 42;
connection.Execute("... where ParentId = $id0$ ... SomethingElse = $id1$ ...",
      new { id0 = id, id1 = id });


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow