Dapper.NET
Parameter Syntax Reference
Sök…
parametrar
Parameter | detaljer |
---|---|
this cnn | Den underliggande databasanslutningen - den this anger en förlängningsmetod; anslutningen behöver inte vara öppen - om den inte är öppen öppnas och stängs den automatiskt. |
<T> / Type | (valfritt) Typ av objekt som ska returneras; om det icke-generiska / icke- Type API används, returneras ett dynamic objekt per rad, som simulerar en egenskap som heter per kolumnnamn som returneras från frågan (detta dynamic objekt implementerar också IDicionary<string,object> ). |
sql | SQL att köra |
param | (valfritt) Parametrarna som ska inkluderas. |
transaction | (valfritt) Den databastransaktion som ska associeras med kommandot |
buffered | (valfritt) Huruvida man ska IEnumerable i en lista (standard), mot att exponera en öppen IEnumerable över live-läsaren |
commandTimeout | (valfritt) Tidsgränsen för kommandot; om det inte anges SqlMapper.Settings.CommandTimeout (om det anges) |
commandType | Typ av kommando som utförs; som standard är CommandText |
Anmärkningar
Syntaxen för att uttrycka parametrar varierar mellan RDBMS. Alla exemplen ovan använder SQL Server-syntax, dvs. @foo
; emellertid ?foo
och :foo
bör också fungera bra.
Grundläggande parametriserad SQL
Dapper gör det enkelt att följa bästa praxis genom fullständigt parametrerad SQL.
Parametrar är viktiga, så dapper gör det enkelt att få det rätt. Du uttrycker bara dina parametrar på det normala sättet för din RDBMS (vanligtvis @foo
?foo
eller :foo
) och ger dapper ett objekt som har en medlem som heter foo
. Det vanligaste sättet att göra detta är med en anonym typ:
int id = 123;
string name = "abc";
connection.Execute("insert [KeyLookup](Id, Name) values(@id, @name)",
new { id, name });
Och det är allt. Dapper lägger till önskade parametrar och allt ska fungera.
Använd din objektmodell
Du kan också använda din befintliga objektmodell som en parameter:
KeyLookup lookup = ... // some existing instance
connection.Execute("insert [KeyLookup](Id, Name) values(@Id, @Name)", lookup);
Dapper använder kommandoteksten för att bestämma vilka medlemmar i objektet som ska läggas till - det kommer vanligtvis inte att lägga till onödiga saker som Description
, IsActive
, CreationDate
eftersom kommandot som vi har utfärdat tydligt inte involverar dem - även om det finns fall då det kan göra det, till exempel om ditt kommando innehåller:
// TODO - removed for now; include the @Description in the insert
Det försöker inte ta reda på att ovanstående bara är en kommentar.
Lagrada förfaranden
Parametrar till lagrade procedurer fungerar exakt samma, förutom att dapper inte kan försöka bestämma vad som ska / bör-inte inkluderas - allt tillgängligt behandlas som en parameter. Av den anledningen föredras vanliga anonyma typer:
connection.Execute("KeyLookupInsert", new { id, name },
commandType: CommandType.StoredProcedure);
Värdeinlining
Ibland kan bekvämligheten hos en parameter (när det gäller underhåll och uttrycksförmåga) uppvägas av dess kostnad i prestanda för att behandla den som en parameter. Till exempel när sidstorleken är fixerad av en konfigurationsinställning. Eller ett enum
matchas med ett enum
. Överväga:
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 });
Den enda riktiga parametern här är customerId
- de andra två är pseudoparametrar som faktiskt inte kommer att ändras. Ofta kan RDBMS göra ett bättre jobb om det upptäcker dessa som konstanter. Dapper har en speciell syntax för detta - {=name}
istället för @name
- som endast gäller numeriska typer. (Detta minimerar all attackyta från SQL-injektion). Ett exempel är följande:
var orders = connection.Query<Order>(@"
select top {=count} *
from Orders
where CustomerId = @customerId
and Status = {=open}", new { customerId, count = PageSize, open = OrderStatus.Open });
Dapper ersätter värden med bokstäver innan han utfärdar SQL, så RDBMS ser faktiskt något som:
select top 10 *
from Orders
where CustomerId = @customerId
and Status = 3
Detta är särskilt användbart när man tillåter RDBMS-system att inte bara fatta bättre beslut utan också öppna frågeformer som faktiska parametrar förhindrar. Till exempel, om en kolumnpredikat är mot en parameter, kan inte ett filtrerat index med specifika värden på de kolumnerna användas. Det beror på att nästa fråga kan ha en parameter förutom ett av de angivna värdena.
Med bokstavliga värden kan sökoptimeraren använda de filtrerade indexen eftersom den vet att värdet inte kan ändras i framtida frågor.
Lista utvidgningar
Ett vanligt scenario i databasfrågor är IN (...)
där listan här genereras vid körning. De flesta RDBMS saknar en bra metafor för detta - och det finns ingen universell cross-RDBMS- lösning för detta. Istället tillhandahåller dapper viss skonsam automatisk kommandoförlängning. Allt som krävs är ett levererat parametervärde som är IEnumerable
. Ett kommando som involverar @foo
utvidgas till (@foo0,@foo1,@foo2,@foo3)
(för en sekvens av 4 objekt). Den vanligaste användningen av detta skulle vara IN
:
int[] orderIds = ...
var orders = connection.Query<Order>(@"
select *
from Orders
where Id in @orderIds", new { orderIds });
Detta utvidgas sedan automatiskt för att utfärda lämplig SQL för flerseriehämtningen:
select *
from Orders
where Id in (@orderIds0, @orderIds1, @orderIds2, @orderIds3)
med parametrarna @orderIds0
etc som läggs till som värden tagna från arrangemanget. Observera att det faktum att det inte är giltigt SQL ursprungligen är avsiktligt för att säkerställa att den här funktionen inte används felaktigt. Den här funktionen fungerar också korrekt med OPTIMIZE FOR
/ UNKNOWN
i SQL Server; om du använder:
option (optimize for
(@orderIds unknown))
det kommer att utvidga detta korrekt till:
option (optimize for
(@orderIds0 unknown, @orderIds1 unknown, @orderIds2 unknown, @orderIds3 unknown))
Att utföra operationer mot flera uppsättningar
Ibland vill du göra samma sak flera gånger. Dapper stöder detta på Execute
metoden om den yttersta parametern (som vanligtvis är en enda anonym typ eller en domänmodellinstans) faktiskt tillhandahålls som en IEnumerable
sekvens. Till exempel:
Order[] orders = ...
// update the totals
connection.Execute("update Orders set Total=@Total where Id=@Id", orders);
Här gör dapper bara en enkel slinga på våra data, i princip samma som om vi hade gjort:
Order[] orders = ...
// update the totals
foreach(Order order in orders) {
connection.Execute("update Orders set Total=@Total where Id=@Id", order);
}
Denna användning blir särskilt intressant när den kombineras med async
API på en anslutning som uttryckligen är konfigurerad till alla "Flera aktiva resultatuppsättningar" - i denna användning kommer dapper automatiskt att leda operationerna, så att du inte betalar latenskostnaden per rad. Detta kräver en lite mer komplicerad användning,
await connection.ExecuteAsync(
new CommandDefinition(
"update Orders set Total=@Total where Id=@Id",
orders, flags: CommandFlags.Pipelined))
Observera dock att du kanske också vill undersöka tabellvärderade parametrar.
Pseudo-Positional Parameters (för leverantörer som inte stöder namngivna parametrar)
Vissa ADO.NET-leverantörer (särskilt: OleDB) stöder inte namngivna parametrar; parametrar specificeras istället endast efter position , med ?
Platshållare. Dapper skulle inte veta vilken medlem att använda för dessa, så dapper tillåter en alternativ syntax ?foo?
; detta skulle vara detsamma som @foo
eller :foo
i andra SQL-varianter, förutom att dapper kommer att ersätta parametertoken helt med ?
innan du kör frågan.
Detta fungerar i kombination med andra funktioner som listutvidgning, så följande är giltigt:
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
och .users
medlemmarna används i enlighet därmed och SQL-emissionen är (till exempel med 3 användare):
select * from Documents
where Region = ?
and OwnerId in (?,?,?)
Observera dock att dapparen inte tillåter att samma parameter används flera gånger när du använder den här funktionen; detta för att förhindra att flera parametervärden (som kan vara stort) läggas till flera gånger. Om du behöver referera till samma värde flera gånger, kan du överväga att förklara en variabel, till exempel:
declare @id int = ?id?; // now we can use @id multiple times in the SQL
Om variabler inte är tillgängliga kan du använda duplikatmedlemnamn i parametrarna - detta kommer också att göra det uppenbart att värdet skickas flera gånger:
int id = 42;
connection.Execute("... where ParentId = $id0$ ... SomethingElse = $id1$ ...",
new { id0 = id, id1 = id });