Ich versuche, die Multimapping-Funktion von dapper zu verwenden, um eine Liste der ProductItems und der zugehörigen Kunden zurückzugeben.
[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; }
}
Mein adretter Code lautet wie folgt
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"
);
Dies funktioniert einwandfrei, aber ich muss anscheinend die vollständige Spaltenliste zum Parameter splitOn hinzufügen, um alle Kundeneigenschaften zurückzugeben. Wenn ich "CustomerName" nicht hinzufüge, wird null zurückgegeben. Verstehe ich die Kernfunktionalität der Multimapping-Funktion nicht? Ich möchte nicht jedes Mal eine vollständige Liste der Spaltennamen hinzufügen müssen.
Antworten:
Ich habe gerade einen Test durchgeführt, der gut funktioniert:
Der splitOn-Parameter muss als Split-Punkt angegeben werden. Der Standardwert ist Id. Wenn mehrere Teilungspunkte vorhanden sind, müssen Sie diese in eine durch Kommas getrennte Liste einfügen.
Angenommen, Ihr Recordset sieht folgendermaßen aus:
Dapper muss wissen, wie die Spalten in dieser Reihenfolge in zwei Objekte aufgeteilt werden. Ein flüchtiger Blick zeigt , dass der Kunde beginnt an der Säule
CustomerId
, alsosplitOn: CustomerId
.Hier gibt es eine große Einschränkung, wenn die Spaltenreihenfolge in der zugrunde liegenden Tabelle aus irgendeinem Grund umgedreht wird:
splitOn: CustomerId
führt zu einem Null-Kundennamen.Wenn Sie
CustomerId,CustomerName
als Teilungspunkte angeben , geht dapper davon aus, dass Sie versuchen, die Ergebnismenge in drei Objekte aufzuteilen. Der erste beginnt am Anfang, der zweite beginnt amCustomerId
, der dritte amCustomerName
.quelle
spliton
, dhCustomerId,CustomerName
nichtCustomerId, CustomerName
, da DapperTrim
die Ergebnisse der Zeichenfolgenaufteilung nicht berücksichtigt . Es wird nur der generische Spliton-Fehler ausgelöst. Hat mich eines Tages verrückt gemacht.Unsere Tabellen haben einen ähnlichen Namen wie Ihre, wobei so etwas wie "CustomerID" möglicherweise zweimal mit einer Operation "select *" zurückgegeben wird. Daher macht Dapper seine Arbeit, teilt sich aber (möglicherweise) zu früh auf, weil die Spalten wie folgt lauten würden:
Dies macht den spliton: -Parameter nicht so nützlich, insbesondere wenn Sie nicht sicher sind, in welcher Reihenfolge die Spalten zurückgegeben werden. Natürlich können Sie Spalten manuell angeben ... aber es ist 2017 und wir tun dies nur noch selten für grundlegende Objektabrufe.
Was wir tun und es hat viele, viele Jahre lang für Tausende von Abfragen hervorragend funktioniert, ist einfach einen Alias für die ID zu verwenden und niemals Spliton anzugeben (unter Verwendung der Standard-ID von Dapper).
... voila! Dapper teilt standardmäßig nur die ID auf, und diese ID wird vor allen Spalten des Kunden angezeigt. Natürlich wird Ihrer Rückgabe-Ergebnismenge eine zusätzliche Spalte hinzugefügt, aber das ist ein äußerst minimaler Aufwand für das zusätzliche Dienstprogramm, genau zu wissen, welche Spalten zu welchem Objekt gehören. Und Sie können dies leicht erweitern. Benötigen Sie Adress- und Länderinformationen?
Das Beste ist, dass Sie in einer minimalen Menge von SQL deutlich zeigen, welche Spalten welchem Objekt zugeordnet sind. Dapper erledigt den Rest.
quelle
Angenommen, die folgende Struktur ist '|' ist der Punkt der Aufteilung und Ts sind die Entitäten, auf die das Mapping angewendet werden soll.
Es folgt die adrette Abfrage, die Sie schreiben müssen.
Wir möchten also, dass TFirst col_1 col_2 col_3 abbildet, für TSecond das col_n col_m ...
Der splitOn-Ausdruck bedeutet:
Starten Sie die Zuordnung aller Spalten zu TFrist, bis Sie eine Spalte mit dem Namen oder Alias 'col_3' finden, und fügen Sie auch 'col_3' in das Zuordnungsergebnis ein.
Starten Sie dann die Zuordnung in TSecond alle Spalten ab 'col_n' und setzen Sie die Zuordnung fort, bis ein neues Trennzeichen gefunden wird. In diesem Fall ist dies 'col_A' und markiert den Beginn der TThird-Zuordnung und so weiter.
Die Spalten der SQL-Abfrage und die Requisiten des Zuordnungsobjekts stehen in einer 1: 1-Beziehung (was bedeutet, dass sie den gleichen Namen haben sollten). Wenn die Spaltennamen, die sich aus der SQL-Abfrage ergeben, unterschiedlich sind, können Sie sie mit 'AS [aliasen Some_Alias_Name] 'Ausdruck.
quelle
Es gibt noch eine Einschränkung. Wenn das Feld CustomerId null ist (normalerweise bei Abfragen mit Linksverknüpfung), erstellt Dapper ProductItem mit Customer = null. Im obigen Beispiel:
Und noch eine Einschränkung / Falle. Wenn Sie das in splitOn angegebene Feld nicht zuordnen und dieses Feld null enthält, erstellt und füllt Dapper das zugehörige Objekt (in diesem Fall Kunde). Um zu demonstrieren, verwenden Sie diese Klasse mit vorherigem SQL:
quelle
Ich mache das generisch in meinem Repo, funktioniert gut für meinen Anwendungsfall. Ich dachte, ich würde teilen. Vielleicht wird jemand dies weiter ausbauen.
Einige Nachteile sind:
Der Code:
quelle
Wenn Sie eine große Entität schreiben müssen, muss jedes Feld eine schwierige Aufgabe sein.
Ich habe versucht, @BlackjacketMack zu beantworten, aber eine meiner Tabellen hat eine ID-Spalte, andere nicht (ich weiß, es ist ein DB-Design-Problem, aber ...), dann wird eine zusätzliche Aufteilung auf dapper eingefügt, deshalb
Funktioniert bei mir nicht Dann habe ich mit einer kleinen Änderung dieser beendet ist , legen Sie einfach eine Split - Punkt mit einem Namen, der mit jedem Feld auf Tabellen nicht übereinstimmt, kann in geändert Fall
as Id
durchas _SplitPoint_
, die letzten SQL - Skript sieht wie folgt aus :Fügen Sie dann in dapper nur einen splitOn hinzu
quelle