Apa cara terbaik untuk menghubungkan konteks basis data Entity Framework (model) ke ViewModel di MVVM WPF?

9

Seperti dalam pertanyaan di atas: Apa cara terbaik untuk memasang model database Entity Framework (konteks) ke viewModel di MVVM (WPF)?

Saya belajar pola MVVM di WPF, banyak contoh yang menunjukkan bagaimana mengimplementasikan model ke viewModel, tetapi model dalam contoh itu hanya kelas-kelas sederhana, saya ingin menggunakan MVVM bersama-sama dengan model kerangka kerja (basis first approach). Whats cara terbaik untuk menghubungkan model ke viewModel.

Terima kasih atas jawabannya.

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

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

Ini adalah ctor yang biasa saya dari ViewModel, pikir ada cara yang lebih baik, saya sedang membaca tentang pola repositori, tidak yakin apakah saya dapat mengadaptasi ini ke WPF MVVM

hal9k2
sumber

Jawaban:

4

Saya telah melihat sedikit ini dan belum menemukan solusi "sempurna". Pola repositori bekerja sangat baik untuk aplikasi MVC di mana konteksnya berumur pendek karena ada dalam controller yang berumur pendek, tetapi masalah terjadi ketika Anda mencoba menerapkan struktur yang sama ke aplikasi WPF di mana VM dapat bertahan untuk jangka waktu yang lama.

Saya telah menggunakan solusi ini di masa lalu yang jauh lebih sederhana daripada banyak pola repo saya telah melihat bahwa upaya untuk mengabstraksi hal-hal ke jumlah yang ekstrem, menghasilkan jumlah kode yang hampir tidak terbaca yang sulit untuk di-debug. Berikut langkah-langkahnya ...

  1. Buat proyek terpisah untuk EDMX untuk bertindak sebagai lapisan akses Data Anda
  2. Buat folder "Repositori" di bawah proyek yang sama
  3. Buat kelas dasar "BaseRepository" untuk bertindak sebagai "Unit Kerja". IDisposableakan memungkinkan Anda untuk menggunakan ini dalam using(){}dan partialakan memungkinkan Anda menerapkan repositori lainnya

    public partial class MyEntityRepository : IDisposable
    {
        MyEntities context = new MyEntities();
    
        public void Dispose()
        {
            context.Dispose();
        }
    }
  4. Buat file lain yang disebut "MyOtherRepository". buat kelas parsial yang sama tetapi terapkan metode berdasarkan apa yang Anda inginkan file itu mengandung

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

Sekarang di VM Anda, Anda dapat melakukan ini ...

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

Ini mengelompokkan semua repositori Anda dalam satu kelas sehingga Anda tidak harus berurusan dengan konteks yang terpisah. Ini memungkinkan Anda mengelola repo yang berbeda dengan mengelompokkan metode ke dalam file yang berbeda dan membantu mencegah duplikasi kode. Di atas semua itu, konteks Anda berumur pendek seperti mereka tanpa menggunakan pola ini.

Kerugiannya adalah bahwa dengan sistem yang lebih besar, Anda mungkin memiliki banyak metode yang dibundel dalam repo Anda. Salah satu solusi dalam hal ini adalah dengan mengimplementasikan beberapa perintah umum dasar seperti "Find" atau "Add", dan mengimplementasikan yang khusus dalam repositori masing-masing.

Sepatu
sumber
2
Anda dapat mengganti konteks EF 'MyEntityRepository' sendiri dan Anda mendapatkan hasil yang sama. Kecuali jika Anda ingin membungkus konteks EF dengan "repositori" Anda sendiri, meningkatkan duplikasi.
Euforia
@ Euphoric Ya Anda bisa, tetapi Anda tidak dijamin bahwa repositori digunakan sesuai konteks. Intinya adalah untuk mengabstraksi cara EF bekerja menjadi persyaratan bisnis sederhana
Sepatu
4

Menentang repositori, yang saya tidak suka. Saya akan merekomendasikan menggunakan pola Command, seperti yang direkomendasikan oleh Ayende .

Secara sederhana, untuk setiap operasi, Anda membuat ThisOperationCommandkelas yang terpisah . Di dalam kelas ini Anda akan bekerja dengan konteks EF normal. Anda bahkan dapat menggunakan beberapa kelas dasar EFCommandyang melakukan beberapa saluran air untuk Anda.

Dari sisi ViewModel, Anda membuat instance dari perintah ini, mengisinya dengan parameter (Anda bahkan dapat melewatkan seluruh instance ViewModel jika Anda tidak keberatan dengan kopling ketat antara perintah dan ViewModel) dan kemudian meneruskannya ke beberapa jenis Executemetode, yang akan mulai perintah, jalankan, robek dan kemudian kembali apa pun yang didapat perintah. Anda juga bisa mengembalikan beberapa nilai jika Anda mendapatkannya dari instance perintah setelah eksekusi.

Keuntungannya adalah Anda tidak perlu menduplikasi seluruh lapisan akses data sebagai repositori dan Anda dapat menggunakan kembali dan menulis perintah selama Anda membuat beberapa infrastruktur sederhana untuk mendukungnya. Misalnya menjalankan perintah dari perintah lain.

Euforia
sumber
0

Untuk skenario sederhana, saya telah menggunakan yang berikut ini:

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

}
Mike
sumber
1
Masalah dengan ini adalah bahwa konteks Anda sekarang berpotensi "berumur panjang".
Sepatu
1
Anda seharusnya tidak membuat instance konteks di dalam kelas, tetapi memasukkannya ke dalam konstruktor.
Oscar Mederos