5

Ho una classe base e due classi derivate.Entity Framework non esegue query sulle classi derivate - Errore in DbOfTypeExpression

Ciascuna delle classi derivate implementa lo stesso tipo di una proprietà - l'unica differenza è il nome della proprietà.

Purtroppo non ho molta influenza sul design della classe -> sono stati generati da un file wsdl.

Quindi ho una proprietà sul BaseType per incapsulare la proprietà comune. Il piano era di usare questa proprietà nei miei viste web ecc

ho usato il famoso "Fruit-Example" per dimostrare il problema:

public class FruitBase 
    { 
     public virtual int ID { get; set; } 


     // 
     // The plan is to use this property in mvc view 
     // 
     [NotMapped] 
     public virtual FruitnessFactor Fruitness 
     { 
      get 
      { 
       if (this.GetType().BaseType == typeof(Apple)) 
        return ((Apple)this).AppleFruitness; 
       else if (this.GetType().BaseType == typeof(Orange)) 
        return ((Orange)this).OrangeFruitness; 
       else 
        return null; 
      } 
     } 
    } 

public class FruitnessFactor { } 

Nel mio controller MVC, la seguente query funziona assolutamente bene :

return View(context.FruitEntities 
          .OfType<Apple>().Include(a =>a.AppleFruitness) 
          .ToList()); 

Ma questo non lo fa:

return View(context.FruitEntities 
            .OfType<Apple>().Include(a =>a.AppleFruitness) 
            .OfType<Orange>().Include(o => o.OrangeFruitness) 
            .ToList()); 

Il messaggio di errore che ottenga è :

DbOfTypeExpression richiede un argomento di espressione con un tipo di risultato polimorfico compatibile con l'argomento type.

Sto utilizzando EF 5.0 RC e l'approccio Code First.

Qualsiasi aiuto è molto apprezzato!

+3

Questo forse perché la tua espressione implica 'Orange' è un' Apple' – Eranga

+0

Avrei pensato definendo il mio FruitEntities come 'DbSet FruitEntities 'l'espressione implica che Orange e Apple sono frutti ?! – Flo

+0

La catena 'OfType' dice:" Filtra tutte le mele da FruitEntities e quindi filtra dal risultato tutte le mele che sono arance ", che ha senso solo se le arance sono mele, ad esempio la classe' Orange' eredita dalla classe 'Apple'. Cosa vuoi ottenere con questa query? Un elenco combinato di arance e mele, cioè tutti i frutti che sono mele ** o ** arance? – Slauma

risposta

7

Per quanto posso dire, non è possibile applicare Include su più sottotipi in una singola query di database. È possibile interrogare un tipo (OfType<Apple>().Include(a => a.AppelFruitness)) e lo stesso per un altro sottotipo. Il problema è che non è possibile concatenare i risultati nella stessa query perché le raccolte di risultati hanno tipi generici diversi (mele e arance).

Un'opzione consisterebbe nell'eseguire due query e copiare la raccolta dei risultati in una nuova raccolta del tipo di base, come già indicato nella sezione dei commenti sotto la domanda.

L'altra opzione (che richiede solo una singola query) è una proiezione. Si dovrà definire un tipo di proiezione (si potrebbe anche proiettare in un tipo anonimo) ...

public class FruitViewModel 
{ 
    public FruitBase Fruit { get; set; } 
    public FruitnessFactor Factor { get; set; } 
} 

... e quindi può utilizzare la query:

List<FruitViewModel> fruitViewModels = context.FruitEntities 
    .OfType<Apple>() 
    .Select(a => new FruitViewModel 
    { 
     Fruit = a, 
     Factor = a.AppleFruitness 
    }) 
    .Concat(context.FruitEntities 
    .OfType<Orange>() 
    .Select(o => new FruitViewModel 
    { 
     Fruit = o, 
     Factor = o.OrangeFruitness 
    })) 
    .ToList(); 

Se non lo fai disattivare il rilevamento delle modifiche (utilizzando AsNoTracking) le proprietà di navigazione vengono popolate automaticamente quando le entità si attaccano al contesto ("Relationship correzione"), il che significa che è possibile estrarre i frutti della collezione ViewModel ...

IEnumerable<FruitBase> fruits = fruitViewModels.Select(fv => fv.Fruit); 

... e avrai i frutti tra cui le proprietà FruitnessFactor.

Questo codice è abbastanza imbarazzante, ma un approccio diretto senza l'utilizzo di una proiezione è stato chiesto più volte senza successo:

+0

Penso che sto andando per la soluzione 2 query. Temo solo un impatto sulle prestazioni se si tiene conto del fatto che ho bisogno di fare ordinamento, impaginazione e cose del genere. Ma finora sembra buono. Saluti! – Flo