2012-05-08 15 views
6

Tablolarım için çoktan çoğa ilişkileri kullanıyorum.LINQ çoktan çoğa ilişkisi, doğru bir WHERE yan tümcesi nasıl yazılır?

var query = from post in context.Posts 
     from tag in post.Tags where tag.TagId == 10 
     select post; 

Tamam, iyi çalışıyor:

bir sorgu var. Kimliğiyle belirtilen etikete sahip yayınları alıyorum.

Etiket kimlikleri koleksiyonum var. Ve koleksiyonumda her etikete sahip yayınlar almak istiyorum. O çalışmıyor

var tagIds = new int[]{1, 3, 7, 23, 56}; 

var query = from post in context.Posts 
     from tag in post.Tags where tagIds.Contains(tag.TagId) 
     select post; 

:

aşağıdaki şekilde deneyin. Sorgu, belirtilen etiketlerden HERHANGİ biri olan tüm gönderileri döndürür.

bir fıkra böyle ama dynamicaly koleksiyonunda etiketlerin herhangi sayım için almak istiyorum:

post.Tags.Whare(x => x.TagId = 1 && x.TagId = 3 && x.TagId = 7 && ...) 
+1

olası yinelenen verilen etiketler linq?] (http://stackoverflow.com/questions/3478874/how-do-i-retrieve-items-that-are-tagged-with-all-the-supplied-tags-in-linq) –

cevap

24
Sen dış sorgudaki her yayının etiketlerini çıkmamalı

; daha ziyade, dış filtrenin kontrolünü gerçekleştiren bir iç sorgu kullanmanız gerekir. (SQL, biz onu bir correlated subquery derdik.)

var query = 
    from post in context.Posts 
    where post.Tags.All(tag => tagIds.Contains(tag.TagId)) 
    select post; 

Alternatif sözdizimi:

var query = 
    context.Posts.Where(post => 
     post.Tags.All(tag => 
      tagIds.Contains(tag.TagId))); 

Düzenleme: Slauma’s clarification başına düzeltme. Aşağıdaki sürüm, en azından tagIds koleksiyonundaki tüm etiketleri içeren gönderileri döndürür.

var query = 
    from post in context.Posts 
    where tagIds.All(requiredId => post.Tags.Any(tag => tag.TagId == requiredId)) 
    select post; 

Alternatif sözdizimi:

var query = 
    context.Posts.Where(post => 
     tagIds.All(requiredId => 
      post.Tags.Any(tag => 
       tag.TagId == requiredId))); 

düzenleme: Slauma başına yukarıda düzeltildi. Ben Transact-SQL NOT EXISTS operatörü simüle etmek .Any() == false kullandım

// Project posts from context for which 
// no Ids from tagIds are not matched 
// by any tags from post 
var query = 
    from post in context.Posts 
    where 
    ( 
     // Project Ids from tagIds that are 
     // not matched by any tags from post 
     from requiredId in tagIds 
     where 
     (
      // Project tags from post that match requiredId 
      from tag in post.Tags 
      where tag.TagId == requiredId 
      select tag 
     ).Any() == false 
     select requiredId 
    ).Any() == false 
    select post; 

: Ayrıca aşağıda sorgu sözdizimi tam yararlanarak başka bir alternatif de dahil olmak üzere.

+2

+1 ile eşleşmeyi istemiyor. Sadece ** BÜTÜN ** tagIds, sadece ** ANK ** – mattytommo

+0

@mattytommo Bu konuda emin misiniz? Bana tüm mesajlar alıyormuş gibi görünüyor. Düzenleme: Sadece ekledi post.Tags.All blok hile yapmak gerekir, ama Tejs ilk vardı. – Trisped

+0

@Trisped, no eşleşmiyor ** ALL ** kimliği tagIds listesinde değil, sadece ** ANK ** – mattytommo

4

Bu aslında yapmak oldukça kolaydır:

var tags = context.Posts.Where(post => post.Tags.All(tag => tagIds.Contains(tag))); 
+0

** ALL ** ile eşleşmek istiyor, sadece 1 – mattytommo

+0

değil, daha sonra 'All' uzantısını kullanarak güncellendi. – Tejs

+0

Bu, * all * etiketlerinin tagIds listesinde yer aldığı iletileri döndürür. Örneğin: tagIds = ("C#", "Java") ve yalnızca "C#" etiketine sahip olan bir gönderi. Sorgunuz bu gönderiyi geri alacaktı. Ancak, "koleksiyonumda ** her etiketin ** bulunduğu gönderiler almak" istiyor. I.e .: Sadece "C#" ** ve ** "Java" ile etiketlenen mesajlar. Belki de, bu oldukça kolay değil mi? :) – Slauma

0

Any ile deneyin.

var query = from post in context.Posts 
    from tag in post.Tags where tagIds.Any(t => t == tag.TagId) 
    select post; 
+0

Eşleşen ** ALL **, sadece 1 – mattytommo

4

Başka bir seçenek hiçbir diğerleri belirttiğiniz kümesi içeren SADECE etiketleri toplanmasını istiyorsanız iki listeyi kesişmesine ve:

var query = from post in context.Posts 
    let tags = post.Tags.Select(x => x.Id).ToList() 
    where tags.Intersect(tagIds).Count() == tags.Length 
    select post; 
[Tüm etiketlenir öğeleri almak nasıl bir
+1

Tag.Intersect (tagIds) .Count() == tagIds.Length'? – Trisped

+0

Bu güzel görünüyor! (@ Trisped'in yorumunda değişiklikle) – Slauma

+0

@Trisped yes, – scottm