Der Titel sagt alles, ich versuche es zu benutzen, aber ich verstehe es nicht. Es ist möglich, dass das Problem ein Mangel an Wissen ist, weil ich ein Amateur bin, aber ich habe ein Dutzend Fragen über dieses Ding gelesen und drei Tage gegoogelt, und ich verstehe es immer noch nicht.
Ich habe so viele Fragen, dass ich mir nicht sicher bin, ob ich das alles nur in einer Frage schreiben soll oder ob jemand alles lesen würde. Wenn jemand eine andere Lösung hat oder denke, ich sollte es in verschiedene Fragen aufteilen ... nun, ich bin offen für Vorschläge.
Ich wollte ein Beispiel schreiben, aber wieder las ich tagelang Dutzende von Beispielen und half mir nicht.
Ich kann mir einfach nicht vorstellen, zu verstehen, wie etwas wie das Beispiel bei GitHub funktioniert:
var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id";
var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;});
Also, Post
haben eine Eigenschaft vom Typ User
und diese Eigenschaft heißt Owner
, richtig? Etwas wie:
public class Post
{
...
public User Owner { get; set;}
}
Daher Query<Post, User, Post>
eine Post
Instanz mit allen Eigenschaften und was nicht, UND erstellt eine User
Instanz und weist sie der Post.Owner
Eigenschaft zu? Wie würden einfache Parameter zu dieser Abfrage hinzugefügt, zum Beispiel wenn jemand die ID als int
Parameter übergeben möchte wie ...WHERE Id = @Id", new {Id = id}
, wo sollte der Parameter hinzugefügt werden, da der Parameter ist jetzt (post, user) => { post.Owner = user; return post;}
? Der Parameter bezieht sich immer auf die angegebenen Typen, Sie können nur die einfachen typischen Parameter für die dynamische Abfrage verwenden, beide können gleichzeitig verwendet werden ? Wie?
Wie kann man unterscheiden, welches DB-Feld zu welchem Objekt gehört? Es macht so etwas wie Klassenname = DB Tabellenname? Was passiert, wenn die Klassen nicht den gleichen Namen wie die DB-Tabelle haben und ich das Attribut [Table]
möchte, wird es funktionieren oder das Attribut ist nur für Dapper.Contrib.Extensions
Methoden? Würde es mit Objekten funktionieren, die dieselbe DB-Tabelle teilen?
In Bezug auf die gleiche Tabelle für verschiedene Objekte Frage, sagen wir, ich habe ein Person
Objekt, die ein BankAccount
Objekt haben:
public class Person
{
...
public BankAccount Account {get; set;}
...
}
public class BankAccount
{
private string _Account;
public string Account
{
get { return _Account; }
set
{
if(!CheckIfIBANIsCorrect(value))
throw new Exception();
_Account = value;
}
}
private bool CheckIfIBANIsCorrect(string IBAN)
{
//...
//Check it
}
}
Ich könnte das String-Konto am selben Tisch wie die Person
speichern, da jede Person über ein einziges Konto verfügt, das von der ID der Person referenziert wird. Wie sollte ich so etwas abbilden? Gibt es sogar einen Weg, sollte ich einfach das Ergebnis in ein dynamisches Objekt laden und dann alle Objekte erstellen, wird Query
den Rest des Person
Objekts erzeugen und ich sollte mich darum kümmern, das verschachtelte Objekt selbst zu erstellen?
Und übrigens, wie soll splitOn
in all dem genutzt werden? Ich verstehe, dass es das Ergebnis in verschiedene "Gruppen" teilen sollte, so dass Sie die Ergebnisse nach IDs fi teilen können und nehmen, was Sie brauchen, aber ich verstehe nicht, wie ich die Informationen aus den verschiedenen "Gruppen" abrufen soll und wie Rückgabe der verschiedenen "Gruppen", Listen, Aufzählungen, was ?.
QueryMultiple
ist eine andere Sache, die weit jenseits meines Verständnisses ist, ob und wieviele Fragen und Antworten ich lese. Sie wissen , ... wie die * tun der .Read
Sache Arbeit? Alles, was ich hier lese oder google, geht davon aus, dass Read
eine Art von Automagie ist, die auf wundersame Weise zwischen Objekten unterscheiden kann. Erneutes Teilen der Ergebnisse nach Klassennamen, so dass ich nur sicher sein muss, dass jedes Objekt den richtigen Tabellennamen hat? Und wieder was passiert mit [Table]
Attribut in diesem Fall?
Ich denke, das Problem, das ich habe, ist, dass ich keine einzige Webseite finden kann, die alles beschreibt (die Beispiele in GitHub sind sehr selten) und ich finde nur noch Antworten auf konkrete Fragen Fälle, die nicht genau das beantworten, was ich zu verstehen versuche, sondern nur jene konkreten Fälle, die mich immer mehr verwirren, während ich sie lese, da jeder eine Menge verschiedener Methoden zu verwenden scheint, ohne zu erklären, WARUM oder WIE.
Ich denke, dass Ihr Hauptproblem bei der Dapper-Abfrage verknüpfter Tabellenabfragen darin besteht, dass das zweite Argument in der Liste immer das Argument "param" ist. Betrachten Sie den folgenden Code:
var productsWithoutCategories = conn.Query<Product>(
"SELECT * FROM Products WHERE ProductName LIKE @nameStartsWith + '%'",
new { nameStartsWith = "a" }
);
Hier gibt es zwei Argumente "sql" und "param" - wenn wir benannte Argumente verwenden, würde der Code wie folgt aussehen:
var productsWithoutCategories = conn.Query<Product>(
sql: "SELECT * FROM Products WHERE ProductName LIKE @nameStartsWith + '%'",
param: new { nameStartsWith = "a" }
);
In Ihrem Beispiel haben Sie
var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;});
Das zweite Argument dort ist eigentlich ein Argument namens "map", das Dapper sagt, wie man Entitäten für Fälle kombiniert, in denen Sie zwei Tabellen in Ihrer SQL-Abfrage verbunden haben. Wenn wir benannte Argumente verwenden würden, würde es so aussehen:
var data = connection.Query<Post, User, Post>(
sql: sql,
map: (post, user) => { post.Owner = user; return post;}
);
Ich werde die Klasse NORTHWND- Datenbank in einem vollständigen Beispiel verwenden. Sagen wir, wir haben die Klassen
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public bool Discontinued { get; set; }
public Category Category { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
und wir möchten eine Liste von Produkten erstellen, wobei der Typ der verschachtelten Kategorie ausgefüllt wird:
using (var conn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
{
var productsWithCategories = conn.Query<Product, Category, Product>(
"SELECT * FROM Products INNER JOIN Categories ON Categories.CategoryID = Products.CategoryID,
map: (product, category) =>
{
product.Category = category;
return product;
},
splitOn: "CategoryID"
);
}
Dies durchläuft alle Zeilen von JOIN'd Product- und Category-Daten und generiert eine Liste eindeutiger Produkte, kann jedoch nicht sicher sein, wie die Category-Daten damit kombiniert werden. Daher ist eine "map" -Funktion erforderlich, die eine Product-Instanz und Eine Category-Instanz, die eine Product-Instanz zurückgeben muss, mit der die Category-Daten verknüpft sind. In diesem Beispiel ist es einfach - wir müssen lediglich die Category-Eigenschaft für die Product-Instanz auf die Category-Instanz festlegen.
Beachten Sie, dass ich einen "splitOn" -Wert angeben musste. Dapper geht davon aus, dass die Schlüsselspalten der Tabellen einfach als "Id" bezeichnet werden, und wenn dies der Fall ist, kann sie automatisch mit Joins dieser Spalten umgehen. In diesem Fall fügen wir jedoch eine Spalte mit dem Namen "CategoryID" hinzu, und daher müssen wir Dapper mitteilen, dass die Daten entsprechend dem Spaltennamen in Produkte und Kategorien aufgeteilt werden sollen.
Wenn wir auch "param" -Objekt angeben möchten, um die Ergebnisse herunterzufiltern, könnten wir Folgendes tun:
var productsWithCategories = conn.Query<Product, Category, Product>(
"SELECT * FROM Products INNER JOIN Categories ON Categories.CategoryID = Products.CategoryID WHERE ProductName LIKE @nameStartsWith + '%'",
map: (product, category) =>
{
product.Category = category;
return product;
},
param: new { nameStartsWith = "a" },
splitOn: "CategoryID"
);
Um Ihre letzte Frage zu beantworten, führt QueryMultiple einfach mehrere Abfragen auf einmal aus und ermöglicht Ihnen dann, sie separat zu lesen. Zum Beispiel, anstatt dies zu tun (mit zwei getrennten Abfragen):
using (var conn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
{
var categories = conn.Query("SELECT * FROM Categories");
var products = conn.Query("SELECT * FROM Products");
}
Sie können eine einzelne SQL-Anweisung angeben, die beide Abfragen in einem Stapel enthält. Sie müssen sie dann jedoch separat aus dem kombinierten Ergebnissatz lesen, der von QueryMultiple zurückgegeben wird:
using (var conn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
{
var combinedResults = conn.QueryMultiple("SELECT * FROM Categories; SELECT * FROM Products");
var categories = combinedResults.Read<Category>();
var products = combinedResults.Read<Product>();
}
Ich denke, dass die anderen Beispiele, die ich von QueryMultiple gesehen habe, ein wenig verwirrend sind, da sie oft einzelne Werte von jeder Abfrage zurückgeben, anstatt vollständige Sätze von Reihen (was in einfachen Abfrageaufrufen häufiger zu sehen ist). Hoffentlich macht das obige das für Sie klar.
Hinweis: Ich habe Ihre Frage zum Attribut [Tabelle] nicht beantwortet. Wenn Sie nach dem Ausprobieren immer noch Probleme haben, würde ich vorschlagen, eine neue Frage zu erstellen. Dapper verwendet den "splitOn" -Wert, um zu entscheiden, wann die Spalten für eine Entität enden und den nächsten Start (im obigen JOIN-Beispiel gab es Felder für Product und dann Felder für Category). Wenn Sie die Category-Klasse in etwas anderes umbenannt haben, dann funktioniert die Abfrage immer noch, Dapper verlässt sich in diesem Fall nicht auf den Tabellennamen - hoffentlich brauchen Sie die [Table] also gar nicht.