Jaki jest najlepszy sposób połączenia kontekstu (modelu) bazy danych Entity Framework z ViewModel w MVVM WPF?

9

Jak w powyższym pytaniu: Jaki jest najlepszy sposób podłączenia modelu bazy danych Entity Framework (kontekst) do viewModel w MVVM (WPF)?

Uczę się wzorca MVVM w WPF, wiele przykładów pokazuje, jak zaimplementować model do viewModel, ale modele w tych przykładach są tylko prostymi klasami, chcę używać MVVM razem z modelem szkieletu encji (pierwsze podejście bazowe). Jaki jest najlepszy sposób na podłączenie modelu do viewModel.

Dziękuję za odpowiedzi.

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

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

To jest mój zwykły ctor ViewModel, myślę, że jest lepszy sposób, czytałem o strukturze repozytorium, nie jestem pewien, czy mogę to dostosować do WPF MVVM

hal9k2
źródło

Odpowiedzi:

4

Spojrzałem na to całkiem sporo i nie znalazłem „idealnego” rozwiązania. Wzorzec repozytorium działa doskonale w aplikacjach MVC, w których kontekst jest krótkotrwały, ponieważ istnieje on w krótkotrwałym kontrolerze, ale problem występuje, gdy próbujesz zastosować tę samą strukturę do aplikacji wpf, w której maszyna wirtualna może utrzymywać się przez długi czas.

W przeszłości korzystałem z tego rozwiązania, które jest o wiele prostsze niż wiele wzorców repo, które widziałem podczas tej próby wyodrębnienia rzeczy do ekstremalnych rozmiarów, co skutkuje prawie nieczytelnymi ilościami kodu, które są trudne do debugowania. Oto kroki ...

  1. Utwórz osobny projekt dla EDMX, który będzie działał jako twoja warstwa dostępu do danych
  2. Utwórz folder „Repozytoria” w ramach tego samego projektu
  3. Utwórz klasę podstawową „BaseRepository”, aby działała jako „Jednostka pracy”. IDisposablepozwoli ci to wykorzystać w a using(){}oraz partialpozwoli ci na implementację innych repozytoriów

    public partial class MyEntityRepository : IDisposable
    {
        MyEntities context = new MyEntities();
    
        public void Dispose()
        {
            context.Dispose();
        }
    }
  4. Utwórz kolejny plik o nazwie „MyOtherRepository”. utwórz tę samą klasę częściową, ale zaimplementuj metody oparte na zawartości pliku

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

Teraz na swojej maszynie wirtualnej możesz to zrobić ...

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

To grupuje wszystkie twoje repozytoria w jednej klasie, więc nie musisz zajmować się osobnym kontekstem. Pozwala lepiej zarządzać różnymi repozytoriami poprzez grupowanie metod w różnych plikach i pomaga zapobiegać powielaniu kodu. Co więcej, twoje konteksty są tak krótkie, jak były bez użycia tego wzorca.

Wadą jest to, że w przypadku większych systemów możesz mieć wiele metod, które są dołączane do repozytorium. Jednym z rozwiązań w tym przypadku byłoby zaimplementowanie podstawowych podstawowych poleceń, takich jak „Znajdź” lub „Dodaj”, oraz zaimplementowanie specjalistycznych poleceń w odpowiednich repozytoriach.

But
źródło
2
Możesz zastąpić własny kontekst EF „MyEntityRepository” i uzyskasz ten sam wynik. Chyba że chcesz owinąć kontekst EF własnym „repozytorium”, zwiększając duplikację.
Euforyczny
@Euphoric Tak, możesz, ale nie masz gwarancji, że repozytorium będzie używane w kontekście. Chodzi o to, aby streścić sposób, w jaki EF działa w proste wymagania biznesowe
Shoe
4

W przeciwieństwie do repozytoriów, których nie lubię. Poleciłbym użyć wzorca poleceń, zgodnie z zaleceniami Ayende .

Mówiąc prosto, dla każdej operacji tworzysz osobną ThisOperationCommandklasę. W tej klasie będziesz pracował z normalnym kontekstem EF. Możesz nawet użyć klasy bazowej, EFCommandktóra wykona za ciebie hydraulikę.

Od strony ViewModel tworzysz instancję tego polecenia, wypełniasz je parametrami (możesz nawet przekazać całą instancję ViewModel, jeśli nie masz nic przeciwko ścisłemu powiązaniu komendy z ViewModel), a następnie przekażesz ją jakiejś Executemetodzie, która się uruchomi wykonać polecenie, wykonać je, rozerwać, a następnie zwrócić wszystko, co otrzymało polecenie. Możesz również zwrócić wiele wartości, jeśli otrzymasz je z instancji polecenia po wykonaniu.

Zaletą jest to, że nie trzeba powielać całej warstwy dostępu do danych jako repozytorium i można ponownie używać i komponować polecenia, o ile tworzy się prostą infrastrukturę do jej obsługi. Na przykład wykonywanie poleceń z innych poleceń.

Euforyk
źródło
0

W przypadku prostych scenariuszy zastosowałem:

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

}
Mikrofon
źródło
1
Problem polega na tym, że twój kontekst jest teraz potencjalnie „długowieczny”.
But
1
Nie powinieneś tworzyć instancji kontekstu wewnątrz klasy, ale wstrzykiwać ją do konstruktora.
Oscar Mederos