2014-09-02 13 views
12

ho attualmente questo codice LINQ/EF nella mia domanda:filtraggio comprende articoli in LINQ e Entity Framework

var rootCategoryItem = DatabaseContext.Categories 
          .Include("SubCategories") 
          .OrderBy(c => c.CategoryOrder) 
          .Single(c => c.CategoryId == 1); 

conosco in EF non è possibile filtrare ancora Accessori inclusi, e posso scrivere del codice LINQ per filtrare le sottocategorie che non sono necessari ... ma il codice LINQ viene convertito in uno SQL assurdo che è altamente non-ottimizzato. Potrei anche scrivere una stored procedure che fa questo (e scrivere una query molto meglio di LINQ), ma ho davvero voglia di utilizzare EF puro.

Così ho lasciato con 2 opzioni (a meno che qualcuno possa vedere le altre opzioni).

Il primo è quello di un ciclo tra le sottocategorie, rimuovere quelli che non sono necessari:

 var subCategoriesToFilter = rootCategoryItem.SubCategories.ToList(); 

     for (int i = 0; i < subCategoriesToFilter.Count; i++) 
     { 
      if (subCategoriesToFilter[i].Deleted) 
       rootCategoryItem.SubCategories.Remove(subCategoriesToFilter[i]); 
     } 

La seconda opzione sarebbe quella di avere questo a mio avviso:

<ul class="treeview ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion ui-widget ui-sortable ui-accordion-content-active"> 
@foreach (var categoryitem in Model.SubCategories.OrderBy(c => c.CategoryOrder)) 
{ 

    @if(!Model.Deleted) 
    { 
     <li class="treelistitem" id="@Model.CategoryId"> 
      <div class="ui-accordion-header ui-state-default ui-corner-all ui-accordion-icons ui-sortable-handle first"> 
      <span class="clickable"> 
       <span class="ui-accordion-header-icon ui-icon treeviewicon treeviewplus"></span> 
       <i class="glyphicon glyphicon-folder-open rightfolderpadding"></i><span class="categoryname">@Model.CategoryName</span> 
      </span> 
      </div> 
      </li> 
    } 
} 
</ul> 

Fuori il 2, quale sarebbe l'opzione migliore? O c'è un'altra opzione che mi manca?

La soluzione

OK, Servy di è più o meno corretta, ho dovuto modificare la sua risposta per farlo funzionare:

 var rootCategoryItem = DatabaseContext.Categories 
      .OrderBy(c => c.CategoryId) 
      .ToList().Select(c => new Category() 
      { 
       SubCategories = c.SubCategories.Where(sub => !sub.Deleted).ToList(), //make sure only undeleted subcategories are returned 
       CategoryId = c.CategoryId, 
       CategoryName = c.CategoryName, 
       Category_ParentID = c.Category_ParentID, 
       CategoryOrder = c.CategoryOrder, 
       Parent_Category = c.Parent_Category, 
       Deleted = c.Deleted 
      }).Single(c => c.CategoryId == 1); 

ho avuto diversi errori che cercano di ottenere la soluzione di Servy a lavorare:

The entity or complex type '.Category' cannot be constructed in a LINQ to Entities query

Cannot implicitly convert type to System.Collections.Generic.ICollection. An explicit conversion exists (are you missing a cast?)

tutto questo è stato risolto con l'aggiunta di ToList() prima che il metodo Select().

+6

Sei sicuro che la tua soluzione sia corretta? Quella ToList() che hai aggiunto caricherà l'intera tabella Categories dal database. –

+0

esattamente quello @JoshMouch detto. funzionerà perché stai restituendo l'intera tabella e quindi utilizzando LinqToEntities sul risultato per filtrarlo ulteriormente. Sto cercando di salvare anche il carico del database :) segnalerò se trovo un modo migliore –

risposta

17

Mentre non è possibile filtrare una raccolta inclusa tramite Include, è possibile utilizzare Select e proiettare tale raccolta in una raccolta filtrata.

var rootCategoryItem = DatabaseContext.Categories 
    .OrderBy(c => c.CategoryOrder) 
    .Select(c => new Category() 
    { 
     SubCategories = c.SubCategories.Where(sub => !sub.Deleted) 
      .OrderBy(sub => sub.CategoryOrder), 
     c.CategoryId, 
     c.CategoryName, 
     //include any other fields needed here 
    }) 
    .Single(c => c.CategoryId == 1); 
+2

Mi piace questa soluzione, tuttavia, ottengo un errore su questa riga: Sottocategorie = c.SubCategories.Where (sub => ! sub.Deleted) .OrderBy (sub => sub.CategoryOrder), Impossibile convertire implicitamente il tipo 'System.Linq.IOrderedEnumerable ' a 'System.Collections.Generic.ICollection '. Esiste una conversione esplicita (ti manca un cast?) – binks

+0

@binks Quindi materializza "IEnumerable' a un' ICollection'. – Servy

+1

Hm ... Ho provato casting (ICollection ) c.SubCategories.Where (sub =>! Sub.Deleted) .OrderBy (sub => sub.CategoryOrder), Anche se che funziona, ho quindi ottenere un nuovo errore: L'entità o il tipo complesso ".Categoria" non può essere costruito in una query LINQ to Entities. – binks

0

Le vostre preoccupazioni qui sono una presentazione preoccupazione (che mostra solo le categorie non eliminati). Ciò indicherebbe il Metodo 2 come la scelta migliore.

TUTTAVIA, ho il sospetto che è necessario utilizzare le categorie non eliminati spesso nel vostro sistema. Ciò indicherebbe che dovresti avere una funzione che restituisca le categorie non cancellate in modo coerente per l'uso ovunque tu ne abbia bisogno.

Per questo motivo, mi sento di raccomandare il metodo 1.

3

ho recon questo modo sembra più pulito e più breve. Non sei sicuro dell'impatto del database

var rootCategoryItem = DatabaseContext.Categories.SingleOrDefault(); 
if (rootCategoryItem == null) return null; 
{ 
    rootCategoryItem.Items = rootCategoryItem ?.Items.Where(x => !x.IsDeleted).ToList(); 
    return rootCategoryItem; 
    } 
Problemi correlati