web-dev-qa-db-fra.com

Join/Where avec LINQ et Lambda

J'ai des problèmes avec une requête écrite en LINQ et Lambda. Jusqu'à présent, je reçois beaucoup d'erreurs, voici mon 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 });

LINQ est nouveau pour moi, je ne suis donc pas sûr que cette requête soit correcte.

353
David

Je trouve que si vous connaissez la syntaxe SQL, l’utilisation de la syntaxe de requête LINQ est beaucoup plus claire, plus naturelle et facilite la détection des erreurs:

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 };

Si vous êtes vraiment bloqué sur l'utilisation de lambdas, votre syntaxe est un peu décalée. Voici la même requête, en utilisant les méthodes d'extension LINQ:

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
825
Daniel Schaffer

Vous pourriez aller de deux manières avec cela. En utilisant LINQPad (inestimable si vous débutez dans LINQ) et une base de données fictive, j'ai construit les requêtes suivantes:

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

ou

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

Dans ce cas particulier, je pense que la syntaxe LINQ est plus propre (je change entre les deux en fonction de ce qui est le plus facile à lire).

Ce que j'aimerais toutefois souligner, c'est que si vous avez la clé étrangère appropriée dans votre base de données (entre post et post_meta), vous n'avez probablement pas besoin d'une jointure explicite sauf si vous essayez de charger un grand nombre d'enregistrements. . Votre exemple semble indiquer que vous essayez de charger un seul message et ses métadonnées. En supposant qu'il existe de nombreux enregistrements post_meta pour chaque message, vous pouvez alors effectuer les opérations suivantes:

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

Si vous souhaitez éviter le problème n + 1, vous pouvez explicitement indiquer à LINQ to SQL de charger tous les éléments associés en une fois (même s’il s’agit peut-être d’une rubrique avancée lorsque vous êtes plus familiarisé avec L2S). L'exemple ci-dessous indique "lorsque vous chargez une publication, chargez également tous les enregistrements qui lui sont associés via la clé étrangère représentée par la propriété 'Post_metas'":

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

Il est possible d'effectuer de nombreux appels LoadWith sur un seul ensemble de DataLoadOptions pour le même type, ou de nombreux types différents. Si vous faites cela souvent, vous voudrez peut-être simplement envisager la mise en cache.

61
Damian Powell

Vos sélecteurs de clé sont incorrects. Ils doivent prendre un objet du type de la table en question et renvoyer la clé à utiliser dans la jointure. Je pense que vous voulez dire ceci:

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

Vous pouvez appliquer la clause where par la suite, pas dans le cadre du sélecteur de clé.

32
Mark Byers

Daniel a une bonne explication des relations syntaxiques, mais j'ai préparé ce document pour que mon équipe puisse le comprendre un peu plus facilement. J'espère que cela aide quelqu'un  enter image description here

24
Talspaugh27

Publier parce que quand j'ai commencé LINQ + EntityFramework, j'ai observé ces exemples pendant un jour.

Si vous utilisez EntityFramework et que vous avez une propriété de navigation nommée Meta dans la configuration de votre objet modèle Post, la tâche est extrêmement simple. Si vous utilisez entity et n'avez pas cette propriété de navigation, qu'attendez-vous?

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

Si vous commencez par écrire du code, vous devez configurer la propriété comme suit:

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

J'ai fait quelque chose comme ça;

var certificationClass = _db.INDIVIDUALLICENSEs
    .Join(_db.INDLICENSECLAsses,
        IL => IL.LICENSE_CLASS,
        ILC => ILC.NAME,
        (IL, ILC) => new { INDIVIDUALLICENSE = IL, INDLICENSECLAsse = ILC })
    .Where(o => 
        o.INDIVIDUALLICENSE.GLOBALENTITYID == "ABC" &&
        o.INDIVIDUALLICENSE.LICENSE_TYPE == "ABC")
    .Select(t => new
        {
            value = t.PSP_INDLICENSECLAsse.ID,
            name = t.PSP_INDIVIDUALLICENSE.LICENSE_CLASS,                
        })
    .OrderBy(x => x.name);
3
Mahib

Cela pourrait être quelque chose comme

var myvar = from a in context.MyEntity
            join b in context.MyEntity2 on a.key equals b.key
            select new { prop1 = a.prop1, prop2= b.prop1};
2
pepitomb

Cette requête linq devrait fonctionner pour vous. Il aura tous les messages qui ont post meta. 

var query = database.Posts.Join(database.Post_Metas,
                                post => post.postId, // Primary Key
                                meta => meat.postId, // Foreign Key
                                (post, meta) => new { Post = post, Meta = meta });

Requête SQL équivalente 

Select * FROM Posts P
INNER JOIN Post_Metas pm ON pm.postId=p.postId
0
Ahamed Ishak

1 est égal à 1 deux jointures de table différentes

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