564 Stimmen

Join/Where mit LINQ und Lambda

Ich habe Probleme mit einer Abfrage in LINQ und Lambda geschrieben. Bisher bekomme ich eine Menge von Fehlern hier ist mein Code:

int id = 1;
var query = database.Posts.Join(database.Post_Metas,
                                post => database.Posts.Where(x => x.ID == id),
                                meta => database.Post_Metas.Where(x => x.Post_ID == id),
                                (post, meta) => new { Post = post, Meta = meta });

Ich bin neu bei der Verwendung von LINQ, daher bin ich nicht sicher, ob diese Abfrage korrekt ist.

14 Stimmen

Was wollen Sie erreichen?

4 Stimmen

Was soll die Abfrage in einem Satz bewirken?

6 Stimmen

Ihre wichtigsten Selektoren sind Weg zu kompliziert. Wenn Sie nach der ID auswählen möchten, reicht x=>x.ID aus.

1290voto

Daniel Schaffer Punkte 54690

Wenn Sie mit der SQL-Syntax vertraut sind, finde ich, dass die LINQ-Abfragesyntax viel klarer und natürlicher ist und es einfacher macht, Fehler zu erkennen:

var id = 1;
var query =
   from post in database.Posts
   join meta in database.Post_Metas on post.ID equals meta.Post_ID
   where post.ID == id
   select new { Post = post, Meta = meta };

Wenn Sie wirklich auf die Verwendung von Lambdas stecken aber, Ihre Syntax ist ziemlich viel aus. Hier ist die gleiche Abfrage, unter Verwendung der LINQ-Erweiterungsmethoden:

var id = 1;
var query = database.Posts    // your starting point - table in the "from" statement
   .Join(database.Post_Metas, // the source table of the inner join
      post => post.ID,        // Select the primary key (the first part of the "on" clause in an sql "join" statement)
      meta => meta.Post_ID,   // Select the foreign key (the second part of the "on" clause)
      (post, meta) => new { Post = post, Meta = meta }) // selection
   .Where(postAndMeta => postAndMeta.Post.ID == id);    // where statement

96voto

Damian Powell Punkte 8397

Man kann das auf zwei Arten angehen. Verwendung von LINQPad (von unschätzbarem Wert, wenn Sie neu in LINQ sind) und eine Dummy-Datenbank, habe ich die folgenden Abfragen erstellt:

Posts.Join(
    Post_metas,
    post => post.Post_id,
    meta => meta.Post_id,
    (post, meta) => new { Post = post, Meta = meta }
)

oder

from p in Posts
join pm in Post_metas on p.Post_id equals pm.Post_id
select new { Post = p, Meta = pm }

In diesem speziellen Fall halte ich die LINQ-Syntax für sauberer (ich wechsle zwischen den beiden, je nachdem, was am einfachsten zu lesen ist).

Ich möchte jedoch darauf hinweisen, dass Sie, wenn Sie geeignete Fremdschlüssel in Ihrer Datenbank haben (zwischen post und post_meta), wahrscheinlich keine explizite Verknüpfung benötigen, es sei denn, Sie versuchen, eine große Anzahl von Datensätzen zu laden. Ihr Beispiel scheint darauf hinzudeuten, dass Sie versuchen, einen einzelnen Beitrag und seine Metadaten zu laden. Angenommen, es gibt viele post_meta-Datensätze für jeden Beitrag, dann könnten Sie Folgendes tun:

var post = Posts.Single(p => p.ID == 1);
var metas = post.Post_metas.ToList();

Wenn Sie das n+1-Problem vermeiden möchten, können Sie LINQ to SQL explizit anweisen, alle zugehörigen Elemente in einem Durchgang zu laden (obwohl dies ein Thema für Fortgeschrittene sein könnte, wenn Sie mit L2S besser vertraut sind). Im folgenden Beispiel heißt es: "Wenn Sie einen Beitrag laden, laden Sie auch alle Datensätze, die über den Fremdschlüssel, der durch die Eigenschaft 'Post_metas' repräsentiert wird, mit ihm verbunden sind":

var dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Post>(p => p.Post_metas);

var dataContext = new MyDataContext();
dataContext.LoadOptions = dataLoadOptions;

var post = Posts.Single(p => p.ID == 1); // Post_metas loaded automagically

Es ist möglich, viele LoadWith Anrufe bei einem einzigen Satz von DataLoadOptions für denselben Typ oder für viele verschiedene Typen. Wenn Sie dies jedoch häufig tun, sollten Sie eine Zwischenspeicherung in Betracht ziehen.

76voto

Talspaugh27 Punkte 893

Daniel hat eine gute Erklärung der Syntaxbeziehungen, aber ich habe dieses Dokument für mein Team zusammengestellt, um es für sie ein wenig einfacher zu machen. Hoffentlich hilft das jemandem enter image description here

0 Stimmen

@Talspaugh27 Warum wird dann in der SQL-Abfrage eine Verknüpfung mit gStatus auf g.id vorgenommen? Ist das ein Fehler oder beabsichtigt?

0 Stimmen

@Drammy in einer Sql-Tabelle muss jede Spalte einen Namen haben. Da es sich um eine 1-Spalten-Tabelle handelt, in der nur die IDs gespeichert werden sollen, habe ich einfach eine Spalte mit dem Namen id verwendet, die List<int> hat dieses Problem nicht. Wenn ich es so eingerichtet hätte public class IdHolder{ int id } dann dieses Objekt in gStatus verwendet List<IdHolder> gStatus = new List<IdHolder>(); gStatus.add(new IdHolder(){id = 7}); gStatus.add(new IdHolder(){id = 8}); dann hätte es die Linq wie folgt geändert t =>t.value.TaskStatusId, g=>g.id Ist diese Änderung sinnvoll?

0 Stimmen

@Talspaugh27 Ja, sicher, ich schätze, ich habe nur gefragt, ob die Syntax im Bild kompiliert werden kann (aber ich könnte es auch einfach selbst testen!). Danke

41voto

Mark Byers Punkte 761508

Ihre Schlüsselwahlen sind falsch. Sie sollten ein Objekt vom Typ der fraglichen Tabelle nehmen und den Schlüssel zurückgeben, der in der Verknüpfung verwendet werden soll. Ich denke, Sie meinen dies:

var query = database.Posts.Join(database.Post_Metas,
                                post => post.ID,
                                meta => meta.Post_ID,
                                (post, meta) => new { Post = post, Meta = meta });

Sie können die Where-Klausel nachträglich anwenden, nicht als Teil des Schlüsselselektors.

9voto

Andy V Punkte 937

Posting, weil, wenn ich begann LINQ + EntityFramework, starrte ich auf diese Beispiele für einen Tag.

Wenn Sie EntityFramework verwenden und eine Navigationseigenschaft namens Meta zu Ihrem Post Modellobjekt eingerichtet haben, ist dies denkbar einfach. Wenn Sie eine Entität verwenden und diese Navigationseigenschaft nicht haben, worauf warten Sie dann noch?

database
  .Posts
  .Where(post => post.ID == id)
  .Select(post => new { post, post.Meta });

Wenn Sie zuerst den Code eingeben, müssen Sie die Eigenschaft folgendermaßen einrichten:

class Post {
  [Key]
  public int ID {get; set}
  public int MetaID { get; set; }
  public virtual Meta Meta {get; set;}
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X