Qual è il modo migliore per collegare il contesto del database Entity Framework (modello) a ViewModel in MVVM WPF?


9

Come nella domanda precedente: qual è il modo migliore per collegare il modello di database (contesto) di Entity Framework per visualizzare il modello in MVVM (WPF)?

Sto imparando il modello MVVM in WPF, molti esempi mostrano come implementare il modello per viewModel, ma i modelli in quegli esempi sono solo semplici classi, voglio usare MVVM insieme al modello di framework di entità (primo approccio di base). Qual è il modo migliore per collegare il modello a viewModel.

Grazie per le risposte

//ctor of ViewModel 
public ViewModel()
{ 
db = new PackageShipmentDBEntities(); // Entity Framework generated class

ListaZBazy = new ObservableCollection<Pack>(db.Packs.Where(w => w.IsSent == false)); 
}

Questo è il mio solito ctor di ViewModel, penso che ci sia un modo migliore, stavo leggendo sul modello di repository, non sono sicuro di poterlo adattare a WPF MVVM

Risposte:


4

Ho esaminato un po 'questo e non ho trovato una soluzione "perfetta". Il modello di repository funziona meravigliosamente per le applicazioni MVC in cui il contesto è di breve durata perché esiste in un controller di breve durata, ma il problema si verifica quando si tenta di applicare la stessa struttura a un'app wpf in cui la VM può persistere per lunghi periodi di tempo.

Ho usato questa soluzione in passato, che è molto più semplice di molti dei modelli di repository che ho visto tentare di sottrarre le cose a un livello estremo, risultando in quantità quasi illeggibili di codice che sono difficili da eseguire il debug. Ecco i passaggi ...

  1. Creare un progetto separato affinché EDMX funga da livello di accesso ai dati
  2. Creare una cartella "Archivi" nello stesso progetto
  3. Creare una classe base "BaseRepository" per fungere da "Unità di lavoro". IDisposableti permetterà di usarlo in a using(){}e partialti permetterà di implementare altri repository

    public partial class MyEntityRepository : IDisposable
    {
        MyEntities context = new MyEntities();
    
        public void Dispose()
        {
            context.Dispose();
        }
    }
  4. Crea un altro file chiamato "MyOtherRepository". creare la stessa classe parziale ma implementare metodi basati su ciò che si desidera contenere quel file

    public partial class MyEntityRepository
    {
        public void MyOtherMethodSave(EntityObject obj)
        {
            //work with context
            ...
    
            context.SaveChanges();
        }
    }

Ora nella tua VM puoi farlo ...

using(MyEntityRepository repo = new MyEntityRepository())
{
     repo.MyOtherMethodSave(objectToSave);
}

Questo raggruppa tutti i tuoi repository in un'unica classe in modo da non dover affrontare un contesto separato. Ti consente di gestire meglio diversi repository raggruppando i metodi in file diversi e aiuta a prevenire la duplicazione del codice. Inoltre, i tuoi contesti hanno la vita breve come lo erano senza usare questo schema.

Lo svantaggio è che con i sistemi più grandi, potresti avere molti metodi che vengono raggruppati sotto il tuo repository. Una soluzione in tal caso sarebbe quella di implementare alcuni comandi comuni di base come "Trova" o "Aggiungi" e implementare quelli specializzati nei rispettivi repository.


2
È possibile sostituire il contesto di EF "MyEntityRepository" e ottenere lo stesso risultato. A meno che non si desideri avvolgere il contesto di EF con il proprio "repository", aumentando la duplicazione.
Euforico

@Euforico Sì, è possibile, ma non è garantito che il repository sia utilizzato nel contesto. Il punto è quello di sottrarre il modo in cui EF lavora in semplici requisiti aziendali
Shoe

4

Opposto ai repository, che non mi piacciono. Consiglierei di usare il modello di comando, come raccomandato da Ayende .

Detto semplicemente, per ogni operazione, si crea una ThisOperationCommandclasse separata . All'interno di questa classe lavorerai con il normale contesto EF. Potresti persino usare una classe base EFCommandche ti fa un po 'di idraulica.

Dal punto di vista ViewModel, si crea l'istanza di questo comando, lo si riempie di parametri (è anche possibile passare l'intera istanza di ViewModel se non si dispiace accoppiamento stretto tra il comando e ViewModel) e quindi passarlo a un tipo di Executemetodo, che inizierà il comando, eseguilo, abbattilo e poi restituisci qualunque cosa il comando abbia ottenuto. È inoltre possibile che restituisca più valori se lo si ottiene dall'istanza del comando dopo l'esecuzione.

Il vantaggio è che non è necessario duplicare l'intero livello di accesso ai dati come repository e è possibile riutilizzare e comporre comandi purché si crei un'infrastruttura semplice per supportarlo. Ad esempio, eseguendo comandi da altri comandi.


0

Per scenari semplici ho usato quanto segue:

public class ViewModel : IDisposable {

    private EntitiesContext _context = new EntitiesContext();

    private SomeEntity _model;
    public SomeEntity Model {
       get { return _model; }
    }

    public View(int id) {
        _model = _context.SomeEntity.Find(id);
    }

    private ICommand _saveCommand = new RelayCommand(() => _context.SaveChanges());
    public ICommand SaveCommand {
        get { return _saveCommand; }
    }        

    public void Dispose() {
         _context.Dispose();
    }

}

1
Il problema è che il tuo contesto ora è potenzialmente "longevo".
Scarpa

1
Non dovresti creare l'istanza del contesto all'interno della classe, ma iniettarla invece nel costruttore.
Oscar Mederos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.