Как реализовывать добавление данных? C# WPF MVVM
Положение дел:
Я изучаю MVVM. Если я не ошибаюсь, то Model нужен нам для того, чтобы реализовывать в нём бизнес-логику (сервис), а ViewModel нужен, чтобы сделать при помощи него привязку данных между View и Model.
Сама проблема:
Где реализовать добавление данных в базу данных? В ViewModel или Model?
На данный момент это реализовано в ViewModel:
public ICommand AddRoomCommand =>
_addRoomCommand ??
(_addRoomCommand = new RelayCommand(
() =>
{
Context.Rooms.Add(new Room
{
Number = RoomInfo.Number,
Type = RoomInfo.Type
});
Context.SaveChanges();
},
() =>
{
if (string.IsNullOrEmpty(RoomInfo.Number) || RoomInfo.Type == RoomTypes.None)
{
return false;
}
return true;
}));
Кстати, вот Model Room:
public class Room : INotifyPropertyChanged
{
private RoomTypes _type;
private string _number;
private int _roomId;
private IList<Client> _clients;
public int RoomId
{
get => _roomId;
set
{
if (value == _roomId) return;
_roomId = value;
OnPropertyChanged();
}
}
public string Number
{
get => _number;
set
{
if (value == _number) return;
_number = value;
OnPropertyChanged();
}
}
public RoomTypes Type
{
get => _type;
set
{
if (value == _type) return;
_type = value;
OnPropertyChanged();
}
}
public virtual IList<Client> Clients
{
get => _clients;
set
{
if (Equals(value, _clients)) return;
_clients = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Room()
{
_clients = new List<Client>();
}
}
Если всё-таки нужно делать это в Model, то, пожалуйста, расскажите как сделать это лучше всего.
Этот проект не мой, я взял его отсюда: https://github.com/mentapro/HotelSystem
Ответы (1 шт):
Model может быть не только бизнес-логикой, но и просто данными. Разделяйте как Вам удобно.
Вот пример работы с БД. Для начала я определил Model(Cat) - грубо говоря хранилище данных. Интерфейс IDataStore<T> который необходимо будет реализовывать каждому классу для работы с конкретнойModel.
Наша Model:
class Cat
{
public int Id { get; set; }
public string Name{ get; set; }
}
Логика для работы с нашей Model
interface IDataStore<T>
{
Task<bool> AddItem(T item);
Task<bool> RemoveItem(int id);
Task<T> GetItem(int id);
Task<IEnumerable<T>> GetItems();
Task<bool> UpdateItem(T item);
}
class CatDataStore<Cat> : IDataStore<Cat>
{
public async Task<bool> AddItem(Cat item)
{
//code
}
public async Task<Cat> GetItem(int id)
{
//code
}
public async Task<IEnumerable<Cat>> GetItems()
{
//code
}
public async Task<bool> RemoveItem(int id)
{
//code
}
public async Task<bool> UpdateItem(Cat item)
{
//code
}
}
Определим BaseViewModel чтобы не писать во всех Model реализацию INotifyPropertyChanged
class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
//Метод будет вызывать OnPropertyChanged для конкретного свойства ViewModel, которое будет забинжено к какому-то UI-элементу во ```View```.
protected bool SetProperty<T>(ref T store, T value,
[CallerMemberName] string prop = "")
{
if (EqualityComparer<T>.Default.Equals(store, value))
return false;
store = value;
OnPropertyChanged(prop);
return true;
}
}
Теперь можно не париться с реализацией INotifyPropertyChanged и просто вызывать метод SetProperty для нужных свойств уже у конкретных ViewModel
class CatViewModel : BaseViewModel
{
private CatDataStore<Cat> _store = new CatDataStore<Cat>();
private string _name;
//Это свойство нужно будет забиндить ко View
public string Name { get => _name; set => SetProperty(ref _name, value); }
public ICommand AddCatCommand
{
get
{
return new Command((_) =>
{
Cat cat = new Cat { Name = this.Name }; //можно и без this, это для наглядности.
_store.AddItem(cat);
});
}
}
}
Класс Command:
class Command : ICommand
{
public event EventHandler CanExecuteChanged;
private Action<object> _execute;
private Func<object, bool> _canExecute;
public Command(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || CanExecute(parameter);
}
public void Execute(object parameter)
{
_execute.Invoke(parameter);
}
}