2011-08-21 13 views
6

mi sono imbattuto al problema successivo ... devo contesto di database:Utilizzando IQueryable <TEntity> invece DbSet <TEntity> problema

// For support unit testing... 
public interface IDbContext : IDisposable 
{ 
    IQueryable<Hardware> Hardwares { get; } 
    IQueryable<ProviderHardware> ProviderHardwares { get; } 
} 

// Real DbContext (EF 4.0, Code First) 
public class PrimaryDbContext : DbContext, IDbContext 
{ 
    public DbSet<Hardware> Hardwares { get; set; } 
    public DbSet<ProviderHardware> ProviderHardwares { get; set; } 

    IQueryable<Hardware> IDbContext.Hardwares 
    { get { return Hardwares; } } 
    IQueryable<ProviderHardware> IDbContext.ProviderHardwares 
    { get { return ProviderHardwares; } } 
    ... 
} 

e cerco ottenere tutte le parti metalliche, che esiste pretende molto nella tabella ProviderHardwares:

var hardwaresRemoved = db.Hardwares.Where(i => (i.IsAvailable == true) && 
    (db.ProviderHardwares.Count(j => j.Article == i.Article) == 0)).ToList(); 

Se uso PrimaryDbContext rigorosamente come "PrimaryDbContext db = new PrimaryDbContext();" tutto funziona bene Ma se lo uso implicitamente "IDbContext db = new PrimaryDbContext();" che ottengo un'eccezione:

Impossibile creare un valore costante di tipo 'ConfiguratorMvcApplication.DomainModels.ProviderHardware'. Solo i tipi primitivi ('come Int32, String e Guid') sono supportati in questo contesto in .

Riassumere, non è possibile sostituire un DbSet su un IQueryable. E come posso usare il test delle unità in questo caso? Spero che qualcuno abbia ancora risolto questo problema ... Grazie in anticipo molto!

+0

Stai dichiarando una costante ovunque nel tuo 'PrimaryDbContext'? –

+0

No, solo che ho dimostrato prima ... E sovrascrivo il metodo OnModelCreating di più ... – xtmq

+0

Posso riprodurlo. Ho anche visto (con SQL Profiler) che nel caso 'IDbContext'' db.ProviderHardwares' all'interno dell'espressione viene eseguito come una query che carica * tutte * 'ProviderHardware' righe dal database (* come se *' IDbContext.ProviderHardwares 'erano un' IEnumerable' e non 'IQueryable'). Quindi il 'Count' e la query esterna non possono essere eseguiti perché l'elenco di oggetti in memoria (elenco di oggetti" costanti ") non può essere utilizzato in SQL. Ciò causa l'eccezione. Perché EF considera 'IDbContext.ProviderHardwares' come un' IEnumerable' ma non 'PrimaryDbContext.ProviderHardwares'? Nessun indizio ... – Slauma

risposta

-2

suggerisco è meglio mantenere DbSets e fare test di integrazionecompreso il database.

Perché, sebbene passare un test di unità con una simulazione di DB potrebbe essere un po 'utile, sarà meglio testare con un database reale (ma non è un test di unità).

In ClassInitialize, cancellare il database e/o creare i dati iniziali per il test.

Se si crea un file App.config con una stringa di connessione, è possibile avere un database di test separato e, se si utilizza prima il codice EF, lo si ottiene gratuitamente.

Cordiali saluti.

+0

Sì, penso che tu abbia ragione ... Ma come posso creare e riempire il database nel codice? Posso creare oggetti di dominio in PrimaryDbContext. Posso creare il database che contiene questi oggetti sul server SQL locale attraverso i primi strumenti del codice EF automaticamente? e usarlo nei miei test? – xtmq

+0

Sì, utilizzando il codice EF Innanzitutto, il database può essere creato e popolato la prima volta che viene eseguita l'app, controllare questo tutorial: (http://www.asp.net/entity-framework/tutorials/creating-an-entity-framework -data-modello-per-un-asp-net-mvc-applicazione). Un ulteriore vantaggio è che se si crea un file App.config nel progetto di test, si ottiene un database di test gratuito, indipendente dal database di sviluppo. Suggerisco di utilizzare SQL Server Compact 4.0. –

+0

Grazie, sto andando a leggere questo manuale =) – xtmq

1

Alla fine ho avuto due proprietà per ogni DbSet: una di tipo IQueryable e una di tipo DbSet. La proprietà IQueryable è definito nell'interfaccia, e trasmette le chiamate verso l'attuazione concreta (proprietà di tipo DbSet), come segue:

// Exists in the interface 
public IQueryable<AccountContact> AccountContacts 
{ 
    get 
    { 
     return DbAccountContacts; 
    } 
    set 
    { 
     DbAccountContacts = (DbSet<AccountContact>)value; 
    } 
} 

// Exists only in the implementation 
public DbSet<AccountContact> DbAccountContacts { get; set; } 

Avere questa configurazione, sono stato in grado di ottenere beffardo per funzionare correttamente e potrebbe unità testare il codice.

Questo è decisamente troppo tardi per l'OP, ma forse questo aiuta qualcuno che sta lottando con la stessa domanda, come ho fatto io.

Problemi correlati