Próbuję użyć funkcji Multimapping dapper, aby zwrócić listę ProductItems i powiązanych klientów.
[Table("Product")]
public class ProductItem
{
public decimal ProductID { get; set; }
public string ProductName { get; set; }
public string AccountOpened { get; set; }
public Customer Customer { get; set; }
}
public class Customer
{
public decimal CustomerId { get; set; }
public string CustomerName { get; set; }
}
Mój elegancki kod jest następujący
var sql = @"select * from Product p
inner join Customer c on p.CustomerId = c.CustomerId
order by p.ProductName";
var data = con.Query<ProductItem, Customer, ProductItem>(
sql,
(productItem, customer) => {
productItem.Customer = customer;
return productItem;
},
splitOn: "CustomerId,CustomerName"
);
Działa to dobrze, ale wydaje mi się, że muszę dodać pełną listę kolumn do parametru splitOn, aby zwrócić wszystkie właściwości klientów. Jeśli nie dodam „CustomerName”, zwraca wartość null. Czy nie rozumiem podstawowych funkcji funkcji multimapping. Nie chcę za każdym razem dodawać pełnej listy nazw kolumn.
Odpowiedzi:
Właśnie przeprowadziłem test, który działa dobrze:
Parametr splitOn musi być określony jako punkt podziału, domyślnie jest to Id. Jeśli istnieje wiele punktów podziału, musisz dodać je na liście rozdzielanej przecinkami.
Powiedz, że Twój zestaw rekordów wygląda następująco:
Dapper musi wiedzieć, jak podzielić kolumny w tej kolejności na 2 obiekty. Pobieżne spojrzenie pokazuje, że klient rozpoczyna się w kolumnie
CustomerId
, stądsplitOn: CustomerId
.Istnieje duże zastrzeżenie, jeśli kolejność kolumn w tabeli bazowej zostanie z jakiegoś powodu odwrócona:
splitOn: CustomerId
spowoduje, że nazwa klienta będzie pusta.Jeśli określisz
CustomerId,CustomerName
jako punkty podziału, dapper zakłada, że próbujesz podzielić zestaw wyników na 3 obiekty. Pierwszy zaczyna się od początku, drugi zaczyna się oCustomerId
, trzeci oCustomerName
.źródło
spliton
, tj.CustomerId,CustomerName
NieCustomerId, CustomerName
, ponieważ Dapper nie maTrim
wyników podziału łańcucha. Po prostu wyrzuci ogólny błąd spliton. Pewnego dnia oszalałem.Nasze tabele mają podobne nazwy do twoich, gdzie coś w rodzaju „IDklienta” może zostać zwrócone dwukrotnie za pomocą operacji „select *”. Dlatego Dapper wykonuje swoją pracę, ale dzieli się zbyt wcześnie (prawdopodobnie), ponieważ kolumny wyglądałyby następująco:
To sprawia, że parametr spliton: nie jest tak przydatny, zwłaszcza gdy nie masz pewności, w jakiej kolejności zwracane są kolumny. Oczywiście możesz ręcznie określić kolumny ... ale jest rok 2017 i po prostu rzadko robimy to już dla podstawowego obiektu.
To, co robimy i działało świetnie dla tysięcy zapytań przez wiele lat, polega po prostu na używaniu aliasu dla Id i nigdy nie określamy spliton (używając domyślnego „Id” Dappera).
... voila! Dapper domyślnie podzieli się tylko na identyfikator, a ten identyfikator występuje przed wszystkimi kolumnami klienta. Oczywiście doda to dodatkową kolumnę do zwracanego zestawu wyników, ale jest to niezwykle minimalne obciążenie dla dodatkowej użyteczności polegającej na dokładnym poznaniu, które kolumny należą do danego obiektu. Możesz to łatwo rozszerzyć. Potrzebujesz informacji o adresie i kraju?
A co najważniejsze, w minimalnej ilości sql wyraźnie pokazujesz, które kolumny są skojarzone z jakim obiektem. Dapper zajmie się resztą.
źródło
Zakładając następującą strukturę, gdzie „|” jest punktem podziału, a Ts to jednostki, do których należy zastosować mapowanie.
Poniżej znajduje się eleganckie zapytanie, które będziesz musiał napisać.
Więc chcemy, aby TFirst mapował col_1 col_2 col_3, a dla TSecond col_n col_m ...
Wyrażenie splitOn przekłada się na:
Rozpocznij mapowanie wszystkich kolumn do TFrist, aż znajdziesz kolumnę o nazwie lub aliasie jako „col_3”, a także dołącz „col_3” do wyniku mapowania.
Następnie rozpocznij mapowanie w TSecond wszystkich kolumn zaczynając od 'col_n' i kontynuuj mapowanie, aż zostanie znaleziony nowy separator, którym w tym przypadku jest 'col_A' i oznacza początek mapowania TThird i tak jeden.
Kolumny zapytania sql i właściwości obiektu mapującego są w relacji 1: 1 (co oznacza, że powinny mieć takie same nazwy), jeśli nazwy kolumn wynikające z zapytania sql są różne, możesz aliasować je za pomocą 'AS [ Some_Alias_Name] ”wyrażenie.
źródło
Jest jeszcze jedno zastrzeżenie. Jeśli pole CustomerId ma wartość null (zwykle w zapytaniach z lewym złączeniem), Dapper tworzy ProductItem z Customer = null. W powyższym przykładzie:
I jeszcze jedno zastrzeżenie / pułapka. Jeśli nie zmapujesz pola określonego w splitOn i to pole zawiera wartość null, Dapper tworzy i wypełnia powiązany obiekt (w tym przypadku Customer). Aby zademonstrować użycie tej klasy z poprzednim sql:
źródło
Robię to ogólnie w moim repozytorium, działa dobrze w moim przypadku użycia. Myślałem, że się podzielę. Może ktoś to jeszcze przedłuży.
Niektóre wady to:
Kod:
źródło
Jeśli musisz zmapować dużą jednostkę, napisanie każdego pola musi być trudnym zadaniem.
Próbowałem odpowiedzieć @BlackjacketMack, ale jedna z moich tabel ma kolumnę Id, inne nie (wiem, że to problem z projektowaniem DB, ale ...) to wstaw dodatkowy podział na elegancki, dlatego
Nie działa na mnie. Następnie zakończyłem małą zmianą w tym, po prostu wstaw punkt podziału z nazwą, która nie pasuje do żadnego pola w tabelach, W przypadku zmiany
as Id
oas _SplitPoint_
, ostateczny skrypt sql wygląda następująco:Następnie w zgrabny sposób dodaj tylko jeden splitOn jako ten
źródło