13 messaggi dal 06 gennaio 2006
Ciao a tutti,
volevo implementare il pattern irepository facendo in modo che il mio repository di base implementasse IQueryable per poterlo utilizzare in modo più agevole direttamente nelle query LINQ.
Questo repository lavorerà con Entity framework e una prima implementazione era questa:


public interface IRepository<T>:IQueryable<T> where T: class, new()
{

}

 public class LegacyEFRepository<T> : IRepository<T> where T : class, new()
 {
        private IUnitOfWork _uow = null;
        private DbSet<T> _set = null;
        DbContext _dbc = null;

        public IEnumerator GetEnumerator()
        {
            return _set.AsEnumerable().GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return _set.AsEnumerable().GetEnumerator();
        }
        public Type ElementType
        {
            get { return typeof(T); }
        }

        public System.Linq.Expressions.Expression Expression
        {
            get
            {
                return (this._set as IQueryable).Expression;
            }
        }

        public IQueryProvider Provider
        {
            get { return _set.AsQueryable().Provider; }
        }

 }


Tutto funzionante fino a che non ho avuto la necessità di utilizzare l'oggetto Local di dbset per verificare prima di fare la query se un oggetto fosse già presente nel modello.

Un esempio è:
1. Aggiungo un oggetto con id=3 senza fare savechanges
2. Ricerco l'oggetto con id=3.

Nell'implementazione attuale l'oggetto 3 è disponibile solo dopo il savechange che effettivamente persiste le informazioni.

Ho provato a lavorare con la proprietà Expression utilizzando anche l'oggetto Local, ma senza successo.

Quanluno si è mai imbattutto in un problema simile? Esiste una soluzione senza dovermi implementare un metodo Fetch che mette insieme il dbset con il Local?

grazie a tutti

Ciao
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
il mio parere personale è che per applicazioni in cui hai una sola fonte dati, il DbContext non vada wrappato dal pattern repository. So che molti lo fanno ma io non ne vedo l'utilità perché l'IDbSet<T> è già un repository.

Se lo vuoi nascondere dietro uno strato di servizi di dominio è un conto, ma il pattern repository in quel caso non aggiunge alcun valore e, anzi, ti sta comunque costringendo ad esporre le proprietà del DbSet sottostante.

ianselmi ha scritto:

un metodo Fetch che mette insieme il dbset con il Local?

Puoi crearti un extension method molto semplice che interroghi per prima cosa la cache locale delle entità tracciate e, solo se non vengono trovati risultati in memoria, rivolgere la query al database. Qui c'è un esempio:
http://weblogs.asp.net/ricardoperes/entity-framework-code-first-get-entities-from-local-cache-or-the-database

ciao,
Moreno

Enjoy learning and just keep making
13 messaggi dal 06 gennaio 2006
Ciao Moreno,
grazie per la risposta.
Ho utilizzato il pattern repository perchè quel pezzo di codice fa parte di un framework più grande dove vorrei la possibilità di non far sapere all'applicativo che tipo di orm/accesso ai dati viene utilizzato per le varie entità in modo da mantenre una certa flessibilità nell'implementazione.
Sono daccordo con te che effettivamente è una doppia implementazione, ma serve per astrarmi dall'implementazione concreta-
Infatti il problema sta proprio qua perchè quello che ritorno con la proprietà Expression non mi permette (almeno per le prove che ho fatto io) di poter gestire una query in locale unita ad una query fatta su db senza fare un metodo agguntivo che implementi explicitamente questa logica.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

ianselmi ha scritto:
Vorrei la possibilità di non far sapere all'applicativo che tipo di orm/accesso ai dati viene utilizzato

Se vuoi isolare l'applicazione dallo strato di persistenza va bene, ma questo implica - in linea -teorica - che sarà isolata anche anche dai ogni suo dettaglio implementativo, compresa la nozione che esiste una collezione locale delle entità cachate.

ianselmi ha scritto:
la proprietà Expression non mi permette (almeno per le prove che ho fatto io) di poter gestire una query in locale unita ad una query fatta su db

L'applicativo non dovrebbe andare a lavorare con la Expression, come a presagire quale sia il comportamento tenuto dall'implementazione concreta del repository.

Hai due strade:
  • Rinunci ad usare la cache locale del Dbset
  • Ti inventi qualcosa nell'implementazione interna di LegacyEFRepository in modo che quando l'applicativo tenta di ottenere l'enumerator, vai per prima cosa a rivolgere l'Expression alla collezione Local e poi, se non produce risultati, la rivolgi invece al DbSet e restituisci i suoi risultati. In questo modo, l'uso della cache, che è un servizio infrastrutturale, è veramente nascosto all'applicativo come - secondo me - dovrebbe essere.


ciao,
Moreno

Enjoy learning and just keep making
13 messaggi dal 06 gennaio 2006
Ciao Moreno,
l'uso della proprietà Expression è automatico implementando IQueryable. Nel codice non lo uso direttamente, quando viene utilizzato in una espressione linq su collezioni di mie entità.
quello che volevo implementare era appunto la seconda soluzione, ma non sono riuscito a trovare la strada giusta per attuarlo.

L'unica idea che al momento funziona è quella di crea un metodo ad hoc (Es. FetchWithLocal) che viene implementato così:
public IQueryable<T> FetchWithLocal(Expression<Func<T, bool>> predicate)
        {
            IQueryable<T> dbResult = this.Where(predicate).ToList().Union(_set.Local).AsQueryable();
            return dbResult;
        }


così facendo ho quello che mi serve, ma devo richiamarlo esplicitamente e non posso utilizzare l'oggetto repository direttamente in query linq, ma devo prima farmi dare un IQueryable e poi utilizzarlo.

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.