Как лучше всего связать контекст (модель) базы данных Entity Framework с ViewModel в MVVM WPF?


9

Как и в приведенном выше вопросе: Как лучше всего связать модель базы данных Entity Framework (контекст) с viewModel в MVVM (WPF)?

Я изучаю шаблон MVVM в WPF, на многих примерах показано, как реализовать модель для viewModel, но модели в этих примерах являются просто простыми классами, я хочу использовать MVVM вместе с моделью структуры сущностей (базовый подход вначале). Какой лучший способ связать модель с viewModel.

Спасибо за ответы.

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

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

Это мой обычный ctor ViewModel, думаю, что есть лучший способ, я читал о шаблоне хранилища, не уверен, смогу ли я адаптировать это к WPF MVVM

Ответы:


4

Я немного разбирался в этом и не нашел «идеального» решения. Шаблон репозитория прекрасно работает для приложений MVC, где контекст недолговечен, поскольку существует в недолговечном контроллере, но проблема возникает, когда вы пытаетесь применить эту же структуру к приложению wpf, где виртуальная машина может сохраняться в течение длительных периодов времени.

В прошлом я использовал это решение, которое было намного проще, чем многие из шаблонов репо, которые я видел, пытаясь абстрагировать вещи до предела, что приводит к почти нечитаемому объему кода, который трудно отладить. Вот шаги ...

  1. Создайте отдельный проект для EDMX, который будет выступать в качестве слоя доступа к данным.
  2. Создайте папку «Репозитории» под тем же проектом
  3. Создайте базовый класс «BaseRepository», который будет действовать как «Единица работы». IDisposableпозволит вам использовать это в using(){}и partialпозволит вам реализовать другие репозитории

    public partial class MyEntityRepository : IDisposable
    {
        MyEntities context = new MyEntities();
    
        public void Dispose()
        {
            context.Dispose();
        }
    }
  4. Создайте другой файл с именем «MyOtherRepository». создать тот же частичный класс, но реализовать методы, основанные на том, что вы хотите, чтобы этот файл содержал

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

Теперь в вашей виртуальной машине вы можете сделать это ...

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

Это группирует все ваши репозитории под одним классом, поэтому вам не нужно иметь дело с отдельным контекстом. Это позволяет вам лучше управлять различными репозиториями, группируя методы в разные файлы, и помогает предотвратить дублирование кода. Кроме того, ваши контексты так же недолговечны, как и без использования этого шаблона.

Недостатком является то, что в более крупных системах у вас может быть много методов, связанных с вашим репо. Одним из решений в этом случае было бы реализовать некоторые основные общие команды, такие как «Найти» или «Добавить», и внедрить специализированные команды в их соответствующие хранилища.


2
Вы можете заменить собственный контекст EF «MyEntityRepository», и вы получите тот же результат. Если вы не хотите обернуть контекст EF своим собственным «хранилищем», увеличивая дублирование.
Эйфорическая

@Euphoric Да, вы могли бы, но тогда вы не гарантированы, что хранилище используется в контексте. Весь смысл в том, чтобы абстрагироваться от того, как EF работает с простыми бизнес-требованиями
Shoe

4

В отличие от хранилищ, которые мне не нравятся. Я бы порекомендовал использовать шаблон Command, как рекомендовано Ayende .

Проще говоря, для каждой операции вы создаете отдельный ThisOperationCommandкласс. Внутри этого класса вы будете работать с обычным EF-контекстом. Вы могли бы даже использовать некоторый базовый класс, EFCommandкоторый делает некоторые сантехнические работы для вас.

Со стороны ViewModel вы создаете экземпляр этой команды, заполняете его параметрами (вы можете даже передать весь экземпляр ViewModel, если не возражаете против тесной связи между командой и ViewModel), а затем передаете его какому-то Executeметоду, который запустится выполнить команду, выполнить ее, разорвать и вернуть то, что получила команда. Вы также можете сделать так, чтобы он возвращал несколько значений, если вы получили его из экземпляра команды после выполнения.

Преимущество состоит в том, что вам не нужно дублировать весь слой доступа к данным в качестве репозитория, и вы можете повторно использовать и составлять команды, если вы создаете некоторую простую инфраструктуру для их поддержки. Например, выполнение команд из других команд.


0

Для простых сценариев я использовал следующее:

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
Проблема в том, что ваш контекст теперь потенциально "долгоживущий".
Чистка

1
Вы не должны создавать экземпляр контекста внутри класса, а вставлять его в конструктор.
Оскар Медерос
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.