Dapper.NET
Syntaxisreferentie parameter
Zoeken…
parameters
Parameter | Details |
---|---|
this cnn | De onderliggende databaseverbinding - this geeft een uitbreidingsmethode aan; de verbinding hoeft niet open te zijn - als deze niet open is, wordt deze automatisch geopend en gesloten. |
<T> / Type | (optioneel) Het type object dat moet worden geretourneerd; als de niet-generieke / niet- Type API wordt gebruikt, wordt per rij een dynamic object geretourneerd, waarbij een eigenschap wordt gesimuleerd die per kolomnaam wordt geretourneerd uit de query (dit dynamic object implementeert ook IDicionary<string,object> ). |
sql | De uit te voeren SQL |
param | (optioneel) De op te nemen parameters. |
transaction | (optioneel) De database-transactie die moet worden gekoppeld aan de opdracht |
buffered | (optioneel) Of de gegevens vooraf in een lijst moeten worden gebruikt (de standaardinstelling), versus het openstellen van een open IEnumerable via de live-lezer |
commandTimeout | (optioneel) De time-out die voor de opdracht moet worden gebruikt; indien niet gespecificeerd, wordt SqlMapper.Settings.CommandTimeout verondersteld (indien gespecificeerd) |
commandType | Het type opdracht dat wordt uitgevoerd; standaard ingesteld op CommandText |
Opmerkingen
De syntaxis voor het uitdrukken van parameters varieert tussen RDBMS. Alle bovenstaande voorbeelden gebruiken SQL Server-syntaxis, dwz @foo
; ?foo
en :foo
zouden echter ook goed moeten werken.
Basic Parameterized SQL
Dapper maakt het gemakkelijk om best practices te volgen via volledig geparametriseerde SQL.
Parameters zijn belangrijk, dus dapper maakt het gemakkelijk om het goed te krijgen. U @foo
gewoon uw parameters op de normale manier uit voor uw RDBMS (meestal @foo
?foo
of :foo
) en geeft dapper een object met een lid genaamd foo
. De meest voorkomende manier om dit te doen is met een anoniem type:
int id = 123;
string name = "abc";
connection.Execute("insert [KeyLookup](Id, Name) values(@id, @name)",
new { id, name });
En dat is het. Dapper voegt de vereiste parameters toe en alles zou moeten werken.
Uw objectmodel gebruiken
U kunt ook uw bestaande objectmodel als parameter gebruiken:
KeyLookup lookup = ... // some existing instance
connection.Execute("insert [KeyLookup](Id, Name) values(@Id, @Name)", lookup);
Dapper gebruikt de opdrachttekst om te bepalen welke leden van het object moeten worden toegevoegd - meestal worden er geen onnodige dingen toegevoegd, zoals Description
, IsActive
, CreationDate
omdat de opdracht die we hebben gegeven er duidelijk niet bij betrokken is - hoewel er gevallen zijn waarin het zou dat kunnen doen, bijvoorbeeld als uw opdracht het volgende bevat:
// TODO - removed for now; include the @Description in the insert
Het probeert niet te achterhalen dat het bovenstaande slechts een opmerking is.
Opgeslagen procedures
Parameters voor opgeslagen procedures werken precies hetzelfde, behalve dat dapper niet kan proberen te bepalen wat wel / niet moet worden opgenomen - alles wat beschikbaar is, wordt behandeld als een parameter. Om die reden hebben anonieme types meestal de voorkeur:
connection.Execute("KeyLookupInsert", new { id, name },
commandType: CommandType.StoredProcedure);
Waarde inlining
Soms kan het gemak van een parameter (in termen van onderhoud en expressiviteit) opwegen tegen de kosten van de prestaties om deze als parameter te behandelen. Bijvoorbeeld wanneer het paginaformaat wordt vastgelegd door een configuratie-instelling. Of een statuswaarde wordt gekoppeld aan een enum
. Overwegen:
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 });
De enige echte parameter hier is customerId
- de andere twee zijn pseudo-parameters die niet echt zullen veranderen. Vaak kan het RDBMS beter werken als het deze als constanten detecteert. Dapper heeft hiervoor een speciale syntaxis - {=name}
plaats van @name
- die alleen van toepassing is op numerieke typen. (Dit minimaliseert elk aanvaloppervlak van SQL-injectie). Een voorbeeld is als volgt:
var orders = connection.Query<Order>(@"
select top {=count} *
from Orders
where CustomerId = @customerId
and Status = {=open}", new { customerId, count = PageSize, open = OrderStatus.Open });
Dapper vervangt waarden door letterlijke waarden voordat de SQL wordt uitgegeven, dus het RDBMS ziet eigenlijk iets als:
select top 10 *
from Orders
where CustomerId = @customerId
and Status = 3
Dit is met name handig wanneer RDBMS-systemen niet alleen betere beslissingen kunnen nemen, maar ook queryplannen kunnen openen die door feitelijke parameters worden voorkomen. Als een kolompredikaat bijvoorbeeld tegen een parameter is, kan een gefilterde index met specifieke waarden voor die kolommen niet worden gebruikt. Dit komt omdat de volgende query een andere parameter kan hebben dan een van die opgegeven waarden.
Met letterlijke waarden kan de queryoptimalisatie gebruikmaken van de gefilterde indexen, omdat het weet dat de waarde niet kan worden gewijzigd in toekomstige query's.
Lijstuitbreidingen
Een veel voorkomend scenario in databasequery's is IN (...)
waarbij de lijst hier tijdens runtime wordt gegenereerd. De meeste RDBMS missen hiervoor een goede metafoor - en hiervoor is geen universele cross-RDBMS- oplossing. In plaats daarvan biedt dapper wat zachte automatische opdrachtuitbreiding. Het enige dat nodig is, is een opgegeven parameterwaarde die IEnumerable
. Een opdracht met @foo
is uitgebreid naar (@foo0,@foo1,@foo2,@foo3)
(voor een reeks van 4 items). Het meest voorkomende gebruik hiervan is IN
:
int[] orderIds = ...
var orders = connection.Query<Order>(@"
select *
from Orders
where Id in @orderIds", new { orderIds });
Dit wordt vervolgens automatisch uitgebreid om de juiste SQL voor het ophalen van meerdere rijen uit te geven:
select *
from Orders
where Id in (@orderIds0, @orderIds1, @orderIds2, @orderIds3)
waarbij de parameters @orderIds0
enz. worden toegevoegd als waarden uit de array. Merk op dat het feit dat het oorspronkelijk geen geldige SQL is, opzettelijk is, om ervoor te zorgen dat deze functie niet ten onrechte wordt gebruikt. Deze functie werkt ook correct met de OPTIMIZE FOR
/ UNKNOWN
query-hint in SQL Server; als je gebruikt:
option (optimize for
(@orderIds unknown))
het zal dit correct uitbreiden tot:
option (optimize for
(@orderIds0 unknown, @orderIds1 unknown, @orderIds2 unknown, @orderIds3 unknown))
Bewerkingen uitvoeren tegen meerdere ingangen
Soms wilt u hetzelfde meerdere keren doen. Dapper ondersteunt dit op de Execute
methode als de buitenste parameter (meestal een enkel anoniem type of een instantie van een domeinmodel) in feite wordt geleverd als een IEnumerable
reeks. Bijvoorbeeld:
Order[] orders = ...
// update the totals
connection.Execute("update Orders set Total=@Total where Id=@Id", orders);
Hier doet dapper gewoon een eenvoudige lus op onze gegevens, in wezen hetzelfde als als we hadden gedaan:
Order[] orders = ...
// update the totals
foreach(Order order in orders) {
connection.Execute("update Orders set Total=@Total where Id=@Id", order);
}
Dit gebruik wordt bijzonder interessant in combinatie met de async
API op een verbinding die expliciet wordt gevormd om alle "Multiple Active Result Sets" - in dit gebruik, dapper automatisch pijpleiding de operaties, zodat u niet betalen van de latency kosten per rij. Dit vereist een iets gecompliceerder gebruik,
await connection.ExecuteAsync(
new CommandDefinition(
"update Orders set Total=@Total where Id=@Id",
orders, flags: CommandFlags.Pipelined))
Houd er echter rekening mee dat u misschien ook tabelparameters wilt onderzoeken.
Pseudo-positionele parameters (voor providers die genoemde parameters niet ondersteunen)
Sommige ADO.NET-providers (met name: OleDB) ondersteunen genoemde parameters niet; parameters worden in plaats daarvan alleen per positie gespecificeerd, met de ?
place-holder. Dapper zou niet weten welk lid hij hiervoor moet gebruiken, dus dapper staat een alternatieve syntaxis toe ?foo?
; dit zou hetzelfde zijn als @foo
of :foo
in andere SQL-varianten, behalve dat dapper het parametertoken volledig zal vervangen door ?
voordat u de query uitvoert.
Dit werkt in combinatie met andere functies zoals lijstuitbreiding, dus het volgende is geldig:
string region = "North";
int[] users = ...
var docs = conn.Query<Document>(@"
select * from Documents
where Region = ?region?
and OwnerId in ?users?", new { region, users }).AsList();
De leden .region
en .users
worden dienovereenkomstig gebruikt en de uitgegeven SQL is (bijvoorbeeld met 3 gebruikers):
select * from Documents
where Region = ?
and OwnerId in (?,?,?)
Merk echter op dat dapper niet toestaat dat dezelfde parameter meerdere keren wordt gebruikt bij het gebruik van deze functie; dit om te voorkomen dat meerdere keren dezelfde parameterwaarde (die groot kan zijn) moet worden toegevoegd. Als u meerdere keren naar dezelfde waarde moet verwijzen, kunt u overwegen een variabele te declareren, bijvoorbeeld:
declare @id int = ?id?; // now we can use @id multiple times in the SQL
Als variabelen niet beschikbaar zijn, kunt u dubbele lidnamen gebruiken in de parameters - dit maakt ook duidelijk dat de waarde meerdere keren wordt verzonden:
int id = 42;
connection.Execute("... where ParentId = $id0$ ... SomethingElse = $id1$ ...",
new { id0 = id, id1 = id });