Quelle est la meilleure façon de câbler le contexte de la base de données Entity Framework (modèle) à ViewModel dans MVVM WPF?


9

Comme dans la question ci-dessus: Quelle est la meilleure façon de câbler le modèle de base de données Entity Framework (contexte) à viewModel dans MVVM (WPF)?

J'apprends le modèle MVVM dans WPF, beaucoup d'exemples montre comment implémenter le modèle pour viewModel, mais les modèles dans ces exemples ne sont que des classes simples, je veux utiliser MVVM avec le modèle de structure d'entité (approche de base). Quelle est la meilleure façon de câbler le modèle pour voir le modèle.

Merci pour les réponses.

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

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

Ceci est mon ctor habituel de ViewModel, pense qu'il y a une meilleure façon, je lisais sur le modèle de référentiel, je ne sais pas si je peux l'adapter à WPF MVVM

Réponses:


4

J'y ai beaucoup réfléchi et je n'ai pas trouvé de solution "parfaite". Le modèle de référentiel fonctionne à merveille pour les applications MVC où le contexte est de courte durée car il existe dans un contrôleur de courte durée, mais le problème se produit lorsque vous essayez d'appliquer cette même structure à une application wpf où la machine virtuelle peut persister pendant de longues périodes.

J'ai utilisé cette solution dans le passé, qui est beaucoup plus simple que la plupart des modèles de repo que j'ai vus et qui tentent d'abstraire les choses à un niveau extrême, résultant en des quantités de code presque illisibles difficiles à déboguer. Voici les étapes ...

  1. Créez un projet distinct pour que l'EDMX agisse comme votre couche d'accès aux données
  2. Créer un dossier "Repositories" sous le même projet
  3. Créez une classe de base "BaseRepository" pour agir comme "Unité de travail". IDisposablevous permettra de l'utiliser dans un using(){}et partialvous permettra de mettre en œuvre d'autres référentiels

    public partial class MyEntityRepository : IDisposable
    {
        MyEntities context = new MyEntities();
    
        public void Dispose()
        {
            context.Dispose();
        }
    }
  4. Créez un autre fichier appelé "MyOtherRepository". créer la même classe partielle mais implémenter des méthodes basées sur ce que vous voulez que ce fichier contienne

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

Maintenant, dans votre machine virtuelle, vous pouvez le faire ...

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

Cela regroupe tous vos référentiels sous une seule classe afin que vous n'ayez pas à gérer un contexte séparé. Il vous permet de mieux gérer différents référentiels en regroupant les méthodes dans différents fichiers et aide à éviter la duplication de code. En plus de cela, vos contextes sont aussi éphémères qu'ils l'étaient sans utiliser ce modèle.

L'inconvénient est qu'avec des systèmes plus grands, vous pouvez avoir beaucoup de méthodes qui sont regroupées sous votre référentiel. Une solution dans ce cas serait d'implémenter certaines commandes communes de base comme "Rechercher" ou "Ajouter", et d'implémenter des commandes spécialisées dans leur référentiel respectif.


2
Vous pouvez remplacer le propre contexte d'EF «MyEntityRepository» et vous obtenez le même résultat. À moins que vous ne vouliez envelopper le contexte d'EF avec votre propre «référentiel», augmentant la duplication.
Euphoric

@Euphoric Oui, vous le pourriez, mais vous n'êtes pas assuré que le référentiel est utilisé dans le contexte. Le but est de résumer la façon dont EF fonctionne dans des exigences commerciales simples
Shoe

4

Opposé aux référentiels, ce que je n'aime pas. Je recommanderais d'utiliser le modèle de commande, comme recommandé par Ayende .

Autrement dit, pour chaque opération, vous créez une ThisOperationCommandclasse distincte . Dans cette classe, vous travaillerez avec un contexte EF normal. Vous pourriez même utiliser une classe de base EFCommandqui fait de la plomberie pour vous.

Du côté de ViewModel, vous créez une instance de cette commande, la remplissez de paramètres (vous pouvez même passer toute l'instance de ViewModel si cela ne vous dérange pas un couplage étroit entre la commande et ViewModel), puis la transmettre à une sorte de Executeméthode, qui démarrera exécutez la commande, exécutez-la, supprimez-la, puis renvoyez ce que la commande a obtenu. Vous pouvez également lui faire retourner plusieurs valeurs si vous l'obtenez à partir de l'instance de la commande après l'exécution.

L'avantage est que vous n'avez pas besoin de dupliquer toute la couche d'accès aux données en tant que référentiel et que vous pouvez réutiliser et composer des commandes tant que vous créez une infrastructure simple pour la prendre en charge. Par exemple, exécuter des commandes à partir d'autres commandes.


0

Pour des scénarios simples, j'ai utilisé ce qui suit:

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
Le problème avec cela est que votre contexte est maintenant potentiellement "de longue durée".
Chaussure du

1
Vous ne devriez pas créer l'instance du contexte à l'intérieur de la classe, mais l'injecter à la place dans le constructeur.
Oscar Mederos
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.