Dapper.NET
Odwołanie do składni parametrów
Szukaj…
Parametry
Parametr | Detale |
---|---|
this cnn | Połączenie podstawowe bazy danych - w this oznacza metodę rozszerzenia; połączenie nie musi być otwarte - jeśli nie jest otwarte, jest otwierane i zamykane automatycznie. |
<T> / Type | (opcjonalnie) Typ obiektu do zwrócenia; jeśli używany jest interfejs API inny niż ogólny / inny niż Type , obiekt dynamic jest zwracany na wiersz, symulując właściwość o nazwie na nazwę kolumny zwróconą z zapytania (ten obiekt dynamic również implementuje IDicionary<string,object> ). |
sql | SQL do wykonania |
param | (opcjonalnie) Parametry do uwzględnienia. |
transaction | (opcjonalnie) Transakcja bazy danych do skojarzenia z poleceniem |
buffered | (opcjonalnie) Określa, czy wstępnie zużyć dane na listę (domyślnie), a nie wyświetlać otwartą IEnumerable w czytniku na żywo |
commandTimeout | (opcjonalnie) Limit czasu do użycia w poleceniu; jeśli nie jest określony, SqlMapper.Settings.CommandTimeout (jeśli określono) |
commandType | Rodzaj wykonywanej komendy; domyślnie jest to CommandText |
Uwagi
Składnia wyrażania parametrów różni się w zależności od RDBMS. Wszystkie powyższe przykłady używają składni SQL Server, tj. @foo
; Jednak ?foo
i :foo
powinny również działać poprawnie.
Podstawowy sparametryzowany SQL
Dapper ułatwia stosowanie najlepszych praktyk dzięki w pełni sparametryzowanemu SQL.
Parametry są ważne, więc eleganckie ułatwia prawidłowe ustawienie. Po prostu wyrażasz swoje parametry w normalny sposób dla swojego RDBMS (zwykle @foo
?foo
lub :foo
) i nadajesz obiektowi, który ma element o nazwie foo
. Najczęstszym sposobem na to jest anonimowy typ:
int id = 123;
string name = "abc";
connection.Execute("insert [KeyLookup](Id, Name) values(@id, @name)",
new { id, name });
I to wszystko. Dapper doda wymagane parametry i wszystko powinno działać.
Korzystanie z modelu obiektowego
Możesz również użyć istniejącego modelu obiektowego jako parametru:
KeyLookup lookup = ... // some existing instance
connection.Execute("insert [KeyLookup](Id, Name) values(@Id, @Name)", lookup);
Dapper używa tekstu polecenia do określenia, którzy członkowie obiektu mają IsActive
- zwykle nie dodaje niepotrzebnych rzeczy, takich jak Description
, IsActive
, CreationDate
ponieważ wydane przez nas polecenie wyraźnie ich nie dotyczy - chociaż zdarzają się przypadki, gdy może to zrobić, na przykład jeśli twoje polecenie zawiera:
// TODO - removed for now; include the @Description in the insert
Nie próbuje dowiedzieć się, że powyższe to tylko komentarz.
Procedury przechowywane
Parametry procedur przechowywanych działają dokładnie tak samo, z tym, że elegancki nie może próbować określić, co powinno / nie powinno być uwzględnione - wszystko dostępne jest traktowane jako parametr. Z tego powodu zwykle preferowane są typy anonimowe:
connection.Execute("KeyLookupInsert", new { id, name },
commandType: CommandType.StoredProcedure);
Inlining wartości
Czasami wygoda parametru (pod względem konserwacji i ekspresji) może być przeważona kosztem wydajności, aby traktować go jako parametr. Na przykład, gdy rozmiar strony jest ustalony przez ustawienie konfiguracji. Lub wartość statusu jest dopasowywana do wartości enum
. Rozważać:
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 });
Jedynym prawdziwym parametrem jest tutaj identyfikator customerId
- pozostałe dwa to pseudo-parametry, które tak naprawdę się nie zmienią. Często RDBMS może wykonać lepszą robotę, jeśli wykryje je jako stałe. Dapper ma do tego specjalną składnię - {=name}
zamiast @name
- która dotyczy tylko typów numerycznych. (Minimalizuje to wszelką powierzchnię ataku po wstrzyknięciu SQL). Przykład jest następujący:
var orders = connection.Query<Order>(@"
select top {=count} *
from Orders
where CustomerId = @customerId
and Status = {=open}", new { customerId, count = PageSize, open = OrderStatus.Open });
Dapper zastępuje wartości literałami przed wydaniem SQL, więc RDBMS faktycznie widzi coś takiego:
select top 10 *
from Orders
where CustomerId = @customerId
and Status = 3
Jest to szczególnie przydatne, gdy pozwala się systemom RDBMS nie tylko podejmować lepsze decyzje, ale także otwierać plany zapytań, którym zapobiegają rzeczywiste parametry. Na przykład, jeśli predykat kolumny jest zgodny z parametrem, wówczas nie można użyć filtrowanego indeksu z określonymi wartościami dla tych kolumn. Wynika to z faktu, że następne zapytanie może zawierać parametr oprócz jednej z tych określonych wartości.
Przy wartościach literalnych optymalizator zapytań może korzystać z filtrowanych indeksów, ponieważ wie, że wartość nie może się zmienić w przyszłych zapytaniach.
Rozszerzenia listy
Częstym scenariuszem w zapytaniach do baz danych jest IN (...)
gdzie lista jest generowana w czasie wykonywania. Większość RDBMS nie ma na to dobrej metafory - i nie ma na to uniwersalnego rozwiązania między RDBMS . Zamiast tego program dapper zapewnia delikatne automatyczne rozszerzanie poleceń. Wszystko, czego wymaga to dostarczona wartość parametru, która jest IEnumerable
. Polecenie obejmujące @foo
jest rozwijane do (@foo0,@foo1,@foo2,@foo3)
(dla sekwencji 4 elementów). Najczęstszym zastosowaniem tego byłoby IN
:
int[] orderIds = ...
var orders = connection.Query<Order>(@"
select *
from Orders
where Id in @orderIds", new { orderIds });
Następnie automatycznie rozszerza się, aby wydać odpowiedni kod SQL dla pobierania wielu wierszy:
select *
from Orders
where Id in (@orderIds0, @orderIds1, @orderIds2, @orderIds3)
z parametrami @orderIds0
itd. dodawanymi jako wartości pobrane z tablicy. Zauważ, że fakt, że oryginalnie nie jest poprawnym SQL, jest celowy, aby upewnić się, że ta funkcja nie zostanie użyta błędnie. Ta funkcja działa również poprawnie z podpowiedzią OPTIMIZE FOR
/ UNKNOWN
w programie SQL Server; Jeśli użyjesz:
option (optimize for
(@orderIds unknown))
rozszerzy to poprawnie do:
option (optimize for
(@orderIds0 unknown, @orderIds1 unknown, @orderIds2 unknown, @orderIds3 unknown))
Wykonywanie operacji na wielu zestawach danych wejściowych
Czasami chcesz zrobić to samo wiele razy. Dapper obsługuje to w metodzie Execute
, jeśli najbardziej zewnętrzny parametr (który jest zwykle pojedynczym anonimowym typem lub instancją modelu domeny) jest faktycznie dostarczany jako sekwencja IEnumerable
. Na przykład:
Order[] orders = ...
// update the totals
connection.Execute("update Orders set Total=@Total where Id=@Id", orders);
Tutaj dapper robi prostą pętlę na naszych danych, zasadniczo tak samo, jakbyśmy to zrobili:
Order[] orders = ...
// update the totals
foreach(Order order in orders) {
connection.Execute("update Orders set Total=@Total where Id=@Id", order);
}
To użycie staje się szczególnie interesujące w połączeniu z async
interfejsem API w połączeniu, które jest jawnie skonfigurowane dla wszystkich „wielu aktywnych zestawów wyników” - w tym zastosowaniu dapper automatycznie potokuje operacje, więc nie płacisz kosztu opóźnienia za wiersz. Wymaga to nieco bardziej skomplikowanego użycia,
await connection.ExecuteAsync(
new CommandDefinition(
"update Orders set Total=@Total where Id=@Id",
orders, flags: CommandFlags.Pipelined))
Pamiętaj jednak, że możesz również chcieć zbadać parametry wyceniane w tabeli.
Parametry pseudo-pozycyjne (dla dostawców, którzy nie obsługują nazwanych parametrów)
Niektórzy dostawcy ADO.NET (w szczególności: OleDB) nie obsługują nazwanych parametrów; zamiast tego parametry są określane tylko według pozycji za pomocą ?
uchwyt na miejsce. Dapper nie wiedziałby, którego członka użyć, więc dapper pozwala na alternatywną składnię, ?foo?
; byłoby to to samo co @foo
lub :foo
w innych wariantach SQL, z tym że dapper całkowicie zastąpi token parametru ?
przed wykonaniem zapytania.
Działa to w połączeniu z innymi funkcjami, takimi jak rozwijanie listy, więc obowiązuje:
string region = "North";
int[] users = ...
var docs = conn.Query<Document>(@"
select * from Documents
where Region = ?region?
and OwnerId in ?users?", new { region, users }).AsList();
Członkowie .region
i .users
są odpowiednio używane, a wydany SQL to (na przykład dla 3 użytkowników):
select * from Documents
where Region = ?
and OwnerId in (?,?,?)
Zauważ jednak, że dapper nie pozwala na wielokrotne użycie tego samego parametru podczas korzystania z tej funkcji; Zapobiega to wielokrotnemu dodawaniu tej samej wartości parametru (która może być duża). Jeśli chcesz wielokrotnie odwoływać się do tej samej wartości, rozważ zadeklarowanie zmiennej, na przykład:
declare @id int = ?id?; // now we can use @id multiple times in the SQL
Jeśli zmienne nie są dostępne, możesz użyć zduplikowanych nazw członków w parametrach - to również sprawi, że będzie oczywiste, że wartość jest wysyłana wiele razy:
int id = 42;
connection.Execute("... where ParentId = $id0$ ... SomethingElse = $id1$ ...",
new { id0 = id, id1 = id });