2015-09-24 23 views
5

Ho visto alcune risposte a domande simili, tuttavia non riesco a capire come applicare la risposta al mio problema.Include condizionale() in Entity Framework

var allposts = _context.Posts 
      .Include(p => p.Comments) 
      .Include(aa => aa.Attachments) 
      .Include(a => a.PostAuthor) 
      .Where(t => t.PostAuthor.Id == postAuthorId).ToList(); 

Gli allegati possono essere caricati dall'autore (tipo Autore) o Collaboratore (tipo Contributor). Quello che voglio fare è ottenere solo gli allegati in cui il proprietario dell'allegato è di tipo Author.

So che questo non funziona e dà un errore:

.Include(s=>aa.Attachments.Where(o=>o.Owner is Author)) 

Ho letto di proiezione filtrata qui

EDIT - link all'articolo: : http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx,

ma Non riesco a capirlo.

Non voglio includere il filtro nella clausola finale dove voglio TUTTI i post, ma voglio solo recuperare gli allegati per quei post che appartengono all'autore.

EDIT 2: - schema Post ha chiesto

public abstract class Post : IPostable 
{ 

    [Key] 
    public int Id { get; set; } 

    [Required] 
    public DateTime PublishDate { get; set; } 

    [Required] 
    public String Title { get; set; } 

    [Required] 
    public String Description { get; set; } 

    public Person PostAuthor { get; set; } 
    public virtual ICollection<Attachment> Attachments { get; set; } 
    public List<Comment> Comments { get; set; } 
} 
+0

Puoi mostrarci lo schema 'Post' per favore? – DarkKnight

+0

@DarkKnight - vedere modifica – grayson

+0

@grayson Quello che stai chiedendo di fare non è possibile. 'Linq2Sql' convertirà il tuo codice in grezzo' SQL', e restituirà le righe figlio tramite un join. Non puoi fare questo tipo di join condizionale in 'SQL'. La tua unica opzione è rimuovere '.Include (aa => aa.Attachments)', e avere una seconda query che restituisce gli allegati a seconda che il proprietario sia o meno un autore/contributore. – Rob

risposta

5

Dal link che hai postato posso confermare che il trucco funziona ma solo per una (molti o molti) rapporti. In questo caso la tua Post-Attachment dovrebbe essere una tantum, quindi è totalmente applicabile. Ecco la domanda si dovrebbe avere:

//this should be disabled temporarily 
_context.Configuration.LazyLoadingEnabled = false; 
var allposts = _context.Posts.Where(t => t.PostAuthor.Id == postAuthorId) 
         .Select(e => new { 
          e,//for later projection 
          e.Comments,//cache Comments 
          //cache filtered Attachments 
          Attachments = e.Attachments.Where(a => a.Owner is Author), 
          e.PostAuthor//cache PostAuthor 
         }) 
         .AsEnumerable() 
         .Select(e => e.e).ToList(); 
+0

devo aggiungere "_context.Configuration.LazyLoadingEnabled = true;" per ricaricare il caricamento lazy dopo questa chiamata? – grayson

+0

@grayson sì, se vuoi riattivarlo. – Hopeless

0

Lambda in Include() possono unico punto a una proprietà:

.Include(a => a.Attachments) 
.Include(a => a.Attachments.Owner); 

la sua condizione non ha senso per me, perché significa Include()join e si o fallo o no. E non condizionatamente.

Come scriveresti in SQL raw?


Perché non solo questo:

context.Attachments 
     .Where(a => a.Owner.Id == postAuthorId && 
        a.Owner.Type == authorType); 

?

+0

Grazie. Sono abbastanza nuovo a tutto questo. Posso farlo per ottenere gli allegati del tipo desiderato, ma non so come unirlo di nuovo al Post. My DisplayTemplate deriva dal post e visualizza Post.Attachments – grayson

3

È possibile utilizzare this implementation di un metodo di estensione Include2() (ad es.). Dopo di che, si può chiamare:

_context.Posts.Include2(post => post.Attachments.Where(a => a.OwnerId == 1)) 

Il codice include sopra solo gli allegati dove Attachment.OwnerId == 1.

+0

Ciao, questo non sembra funzionare quando non ci sono allegati per un post. A, mi manca qualcosa – grayson

1

Rimuovere la parola virtual dalla vostra proprietà di navigazione Attachments Per evitare un pigro:

public ICollection<Attachment> Attachments { get; set; }

Primo metodo: emettere due query separate: una per i messaggi, uno per gli allegati, e lasciare rapporto FIX fino fare il resto:

List<Post> postsWithAuthoredAttachments = _context.Posts 
    .Include(p => p.Comments) 
    .Include(p => p.PostAuthor) 
    .Where(p => p.PostAuthor.Id == postAuthorId) 
    .ToList(); 

List<Attachment> filteredAttachments = _context.Attachments 
    .Where(a => a.Post.PostAuthor.Id == postAuthorId) 
    .Where(a => a.Owner is Author) 
    .ToList() 

correzione di relazione significa che è possibile accedere a questi allegati filtrati tramite proprietà di navigazione di un messaggio

Secondo metodo: una query al database seguito da una query in-memory:

var query = _context.Posts 
    .Include(p => p.Comments) 
    .Include(p => p.PostAuthor) 
    .Where(p => p.PostAuthor.Id == postAuthorId) 
    .Select(p => new 
     { 
      Post = p, 
      AuthoredAttachments = p.Attachments 
       Where(a => a.Owner is Author) 
     } 
    ); 

vorrei solo usare il tipo anonimo qui

var postsWithAuthoredAttachments = query.ToList() 

o vorrei creare una classe ViewModel per evitare il tipo anonimo:

List<MyDisplayTemplate> postsWithAuthoredAttachments = 
    //query as above but use new PostWithAuthoredAttachments in the Select 

Oppure, se si vuole veramente di scartare i messaggi:

0.123.
List<Post> postsWithAuthoredAttachments = query.//you could "inline" this variable 
    .AsEnumerable() //force the database query to run as is - pulling data into memory 
    .Select(p => p) //unwrap the Posts from the in-memory results 
    .ToList() 
-1

Assumendo "a" di tipo "YourType", un include condizionale potrebbe essere risolto utilizzando un'estensione di metodo, ad es.

public static class QueryableExtensions 
{ 
    public static IQueryable<T> ConditionalInclude<T>(this IQueryable<T> source, bool include) where T : YourType 
    { 
     if (include) 
     { 
      return source 
       .Include(a => a.Attachments) 
       .Include(a => a.Attachments.Owner)); 
     } 

     return source; 
    } 
} 

... quindi utilizzare questo come si sta utilizzando. Includi, ad es.

bool yourCondition; 

.ConditionalInclude(yourCondition) 
+3

è uno scherzo o qualcosa del genere? – sam