2012-07-17 13 views
11

Abbiamo un cliente molto grande tavolo con oltre colonne (so che qualcuno lo fa!)Seleziona colonne specifiche dal database utilizzando codice EF Prima

Molte di queste colonne sono infatti chiavi esterne ad altre tabelle.

Abbiamo anche il requisito di carico oneroso alcune delle tabelle correlate.

Esiste un modo in Linq to SQL o Linq dinamico per specificare quali colonne devono essere recuperate dal database? Sto cercando una dichiarazione LINQ che in realtà ha questo effetto sul conto SQL generato:

SELECT Id, Name FROM Book 

Quando si esegue la query reguar generato da EF, SQL Server genera un errore che è stato raggiunto il numero massimo di colonne che può essere selezionato all'interno di una query !!!

Qualsiasi aiuto è molto apprezzato!


Sì, esattamente questo è il caso, la tabella contiene 500 colonne ed è di per sé fa riferimento il nostro strumento di carichi automaticamente ansiosi i primi rapporti di livello e questo colpisce il limite SQL sul numero di colonne che possono essere interrogati.

Speravo che posso impostato solo carico colonne limitate delle entità correlate, come Id e nome (che viene utilizzato nell'interfaccia utente per visualizzare il record per utente)

Credo che l'altra opzione è quella di controlla quali colonne FK dovrebbero essere caricate con entusiasmo. Tuttavia questo rimane ancora un problema per le tabelle che hanno una colonna binary o ntext che potresti non voler caricare tutte le volte.

C'è un modo per collegare più modelli (entità) alla stessa tabella in codice prima? Abbiamo provato a farlo penso che lo sforzo sia fallito miseramente.

risposta

18

Sì, è possibile restituire solo sottoinsieme delle colonne utilizzando la proiezione:

var result = from x in context.LargeTable 
      select new { x.Id, x.Name }; 

Il problema: proiezione e desiderosi di carico non funziona insieme. Una volta che inizi a utilizzare proiezioni o join personalizzati, cambi la forma della query e non puoi utilizzare Include (EF lo ignorerà). L'unico modo in tale scenario è quello di includere manualmente relazioni nel set di risultati proiettata:

var result = from x in context.LargeTable 
      select new { 
       Id = x.Id, 
       Name = x.Name, 
       // You can filter or project relations as well 
       RelatedEnitites = x.SomeRelation.Where(...) 
      }; 

È anche possibile proiettare al tipo specifico ma questo tipo specifico non deve essere mappata (quindi non è possibile, ad esempio progetto LargeTable entità da il mio esempio). La proiezione sull'entità mappata può essere eseguita solo su dati materializzati in Linq-to-objects.

Edit:

C'è probabilmente un malinteso come funziona EF. EF funziona in base alle entità: l'entità è ciò che hai mappato. Se si mappano 500 colonne all'entità, EF usa semplicemente quell'entità come l'hai definita. Significa che l'interrogazione carica entità e persistenza salva entità.

Perché funziona in questo modo? L'entità è considerata una struttura di dati atomici e i suoi dati possono essere caricati e tracciati solo una volta: questa è una caratteristica fondamentale per la capacità di perseguire correttamente le modifiche al database.Ciò non significa che non dovresti caricare solo sottoinsiemi di colonne se ne hai bisogno, ma dovresti capire che il caricamento di sottoinsiemi di colonne non definisce la tua entità originale - è considerata una vista arbitraria sui dati della tua entità. Questa vista non è tracciabile e non può essere riportata al database senza uno sforzo aggiuntivo (semplicemente perché EF non contiene alcuna informazione sull'origine della proiezione).

EF anche luogo alcuni vincoli aggiuntivi la possibilità di mappare l'entità

  • Ogni tabella può essere normalmente mappato solo una volta. Perché? Anche in questo caso, la mappatura di più tabelle a entità diverse può compromettere la capacità di perseguire correttamente tali entità, ad esempio se una colonna non chiave viene mappata due volte e si carica l'istanza di entrambe le entità mappate allo stesso record, che verrà utilizzato durante salvare le modifiche?
  • Ci sono due eccezioni che si permettono di tabella di mapping più volte
    • tabella per gerarchia di ereditarietà - si tratta di una mappatura in cui tavolo può contenere record da più tipi di entità definite nella gerarchia di ereditarietà. Le colonne mappate all'entità di base nella gerarchia devono essere condivise da tutte le entità. Ogni tipo di entità derivata può avere le proprie colonne mappate alle sue proprietà specifiche (altri tipi di entità hanno sempre queste colonne vuote). Non è possibile condividere la colonna per le proprietà derivate tra più entità. Ci deve essere anche una colonna aggiuntiva chiamata discriminatore che indica quale tipo di entità è memorizzato nel record - questa colonna non può essere mappata come proprietà perché è già mappata come discriminante di tipo.
    • Suddivisione tabella: questa è la soluzione diretta per la limitazione della mappatura di una tabella singola. Ti consente di suddividere la tabella in più entità con alcuni vincoli:
      • Ci deve essere una relazione uno a uno tra le entità. Si dispone di un'entità centrale utilizzata per caricare i dati principali e tutte le altre entità sono accessibili tramite le proprietà di navigazione di questa entità. Il caricamento occasionale, il caricamento lento e il caricamento esplicito funzionano normalmente.
      • La relazione è reale 1-1 quindi entrambe le parti o la relazione devono sempre esistere.
      • Le entità non devono condividere i beni ad eccezione del tasto - questo vincolo risolverà il problema iniziale, perché ogni proprietà modificabili viene mappato solo una volta
      • Ogni entità dalla tabella divisa deve avere una proprietà chiave mappata
      • inserimento richiede intero oggetto dati per essere popolato perché altre entità possono contiene mappata colonne richieste

Linq to SQL contiene anche possibilità di contrassegnare una colonna come pigrizia loaded ma THI La funzione s non è attualmente disponibile in EF - è possibile vote for that feature.

Essa conduce alle opzioni per l'ottimizzazione

  • Utilizzare proiezioni per ottenere sola lettura "view" per l'entità
    • Si può fare nella query LINQ come ho mostrato nella parte precedente di questo rispondere
    • è possibile creare vista di database e la mappa come una nuova "entità"
    • in EDMX è anche possibile utilizzare Definire query o vista query per incapsulare sia SQL o la proiezione ESQL nella vostra mappatura
  • Usa tabella scissione
    • EDMX consente tabella divisione di molte entità senza alcun problema
    • Code first allows you splitting table così, ma ci sono alcuni problemi quando si tabella divisa per più di due entità (penso che richiede che ogni tipo di entità per avere proprietà di navigazione per tutti gli altri tipi di entità dalla tabella divisa - che lo rende davvero difficile da usare).
+0

Speravo ci fosse un modo più solido per specificare le colonne. In molti casi la nostra applicazione MVC è condivisa per più modelli e stiamo utilizzando linq dinamico per poter eseguire la stessa query per tabelle diverse. – sam360

+0

Linq dinamico dovrebbe essere in grado di specificare anche la proiezione. EF è lo strumento per lavorare con le entità - l'entità è ciò che hai mappato = se hai mappato 500 colonne all'entità, la tua query senza proiezione restituirà sempre 500 colonne + colonne di tutte le relazioni caricate con interesse. –

+0

Sì, esattamente questo è il caso, la tabella ha 500 colonne ed è autoreferenziale il nostro strumento carica automaticamente le relazioni di primo livello e questo colpisce il limite SQL sul numero di colonne che possono essere interrogate. Speravo di essere in grado di caricare solo colonne limitate delle entità correlate come Id e Nome (che viene utilizzato nell'interfaccia utente per visualizzare il record per l'utente) Immagino che l'altra opzione sia controllare quali colonne dovrebbero sii impaziente. Tuttavia questo rimane ancora un problema per le tabelle che hanno una colonna binary o ntext che potresti non voler caricare tutti i tiems – sam360

0

Creare stored procedure che interrogano il numero di colonne necessarie e quindi chiamare le stored procedure dal codice.

Problemi correlati