¿Cuál es la mejor manera de conectar el contexto de la base de datos de Entity Framework (modelo) a ViewModel en MVVM WPF?

9

Como en la pregunta anterior: ¿Cuál es la mejor manera de conectar el modelo de base de datos de Entity Framework (contexto) para ver el Modelo en MVVM (WPF)?

Estoy aprendiendo el patrón MVVM en WPF, muchos ejemplos muestran cómo implementar el modelo para ver el Modelo, pero los modelos en esos ejemplos son solo clases simples, quiero usar MVVM junto con el modelo de marco de entidad (primer enfoque base). ¿Cuál es la mejor manera de cablear el modelo para ver el modelo?

Gracias por las respuestas

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

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

Este es mi creador habitual de ViewModel, creo que hay una mejor manera, estaba leyendo sobre el patrón de repositorio, no estoy seguro de si puedo adaptar esto a WPF MVVM

hal9k2
fuente

Respuestas:

4

He investigado esto bastante y no he encontrado una solución "perfecta". El patrón de repositorio funciona maravillosamente para aplicaciones MVC donde el contexto es de corta duración porque existe en un controlador de corta duración, pero el problema ocurre cuando intenta aplicar esa misma estructura a una aplicación wpf donde la VM puede persistir por largos períodos de tiempo.

He usado esta solución en el pasado, que es mucho más simple que muchos de los patrones de repositorio que he visto que intentan abstraer las cosas a una cantidad extrema, lo que resulta en cantidades de código casi ilegibles que son difíciles de depurar. Aquí están los pasos ...

  1. Cree un proyecto separado para que EDMX actúe como su capa de acceso a datos
  2. Crear una carpeta "Repositorios" en el mismo proyecto
  3. Cree una clase base "BaseRepository" para actuar como la "Unidad de trabajo". IDisposablele permitirá utilizar esto en una using(){}y partialle permitirá hacer aplicar otros repositorios

    public partial class MyEntityRepository : IDisposable
    {
        MyEntities context = new MyEntities();
    
        public void Dispose()
        {
            context.Dispose();
        }
    }
    
  4. Cree otro archivo llamado "MyOtherRepository". crea la misma clase parcial pero implementa métodos basados ​​en lo que quieres que contenga ese archivo

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

Ahora en tu VM puedes hacer esto ...

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

Esto agrupa todos sus repositorios en una clase para que no tenga que lidiar con un contexto separado. Le permite administrar mejor los diferentes repositorios al agrupar los métodos en diferentes archivos y ayuda a evitar la duplicación de código. Además de eso, sus contextos son tan efímeros como lo fueron sin usar este patrón.

La desventaja es que con sistemas más grandes, puede tener muchos métodos que se agrupan bajo su repositorio. Una solución en ese caso sería implementar algunos comandos comunes básicos como "Buscar" o "Agregar" e implementar otros especializados en sus respectivos repositorios.

Zapato
fuente
2
Puede reemplazar el contexto propio de 'MyEntityRepository' EF y obtendrá el mismo resultado. A menos que desee ajustar el contexto de EF con su propio "repositorio", aumentando la duplicación.
Eufórico
@Euphoric Sí, podrías, pero no tienes la garantía de que el repositorio se use en el contexto. El objetivo es abstraer la forma en que EF funciona en requisitos comerciales simples
Shoe
4

Opuesto a repositorios, que no me gustan. Yo recomendaría el uso de patrón de comando, según lo recomendado por Ayende .

Simplemente dicho, para cada operación, crea una ThisOperationCommandclase separada . Dentro de esta clase trabajarás con el contexto EF normal. Incluso podría usar alguna clase base EFCommandque haga algunas tuberías por usted.

Desde el lado de ViewModel, puede crear una instancia de este comando, llenarlo con parámetros (incluso puede pasar una instancia completa de ViewModel si no le importa un acoplamiento estrecho entre el comando y ViewModel) y luego pasarlo a algún tipo de Executemétodo, que comenzará arriba el comando, ejecútelo, tírelo y luego devuelva lo que haya obtenido. También puede hacer que devuelva varios valores si lo obtiene de la instancia del comando después de la ejecución.

La ventaja es que no necesita duplicar toda la capa de acceso a datos como repositorio y puede reutilizar y redactar comandos siempre que cree una infraestructura simple para admitirlo. Por ejemplo, ejecutar comandos desde otros comandos.

Eufórico
fuente
0

Para escenarios simples, he usado lo siguiente:

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();
    }

}
Miguel
fuente
1
El problema con esto es que su contexto ahora es potencialmente "longevo".
Zapato
1
No debería crear la instancia del contexto dentro de la clase, sino inyectarla en el constructor.
Oscar Mederos