DateTime from = ... int id = ... int count = ... var orders = connection.Query<Order>( @"select top (@count) * from Orders where CustomerId=@id and CreationDate >= @from and Status=@open", new { id, from, count, open=OrderStatus.Open }).ToList();
It is unapologetic about expecting you to know and “own” your SQL – entirely good things, IMO (by comparison: most professionals wouldn't program the web tier without knowing what their html looks like).
Inline value injection
- check the sql to see which possible parameters can definitely be ignored, because they aren’t mentioned (assuming it isn’t a stored procedure, etc)
- parameter expansion (typically used for
in
queries, i.e.where id in @ids
, where@ids
is something like anint[]
)
Alternatively, often the value will never be changed (but is treated as a parameter for code reason), or will only ever be one value unless some configuration setting is changed, maybe twice a year. Classic values here might be a status code from an enum, or the number of rows (
select top 50
sometimes performs quite differently to select top (@rows)
).Because of this, the current builds of dapper introduce value injection. This uses an intentionally different syntax similar to parameters, but injects the value directly into the SQL immediately before execution (but allowing dapper to re-use the strategy). It probably makes more sense with an example:
DateTime from = ... int id = ... int count = ... var orders = connection.Query<Order>( @"select top {=count} * from Orders where CustomerId=@id and CreationDate >= @from and Status={=open}", new { id, from, count, open=OrderStatus.Open }).ToList();
Essentially, anything of the form
{=name}
will be treated as an inlined value, and will be replaced rather than treated as a parameter. Of course, at this point you’re probably screaming “nooooooo! what about sql injection!” – which is why it restricts usage to integer-based types (including enums). This significantly reduces the risk of any abuse, and of course: you don’t have to use it if you don’t want!Parameter expansion support for OPTIMIZE FOR query hints
OPTIMIZE FOR
query hint. This can be left open (applies to all parameters), but it is often desirable to use the variant that tells it exactly which parameters we are concerned about. This is easy normally, but recall that dapper offers parameter expansion. So how can we use this query hint with the in
query above? We don't conveniently know the names of the eventual parameters...Because of this, dapper now recognises this specific pattern, and performs parameter expansion compatible with this hint. If you use:
option (optimize for (@ids unknown))
it will expand this out to the correct query hint for the parameters that
@ids
become during expansion.Async all the things
*Async
method names, but some key additions:- Support for cancellation tokens
- Opt-in use of pipelining (performing a range of operations on a connection without waiting for the early operations to complete – this requires MARS to be enabled)