Нужна ли обертка над моделями представления для управления вложенностями и как управлять вложенностями в части сериализации и десериализации

Есть классы VM:

public class SyllabusVM
{
    public string TitleSyllabus { get; set; } = string.Empty;
    public List<SemestrVM>? Semesters { get; set; }
}
public class SemestrVM
{
    public int Number { get; set; }
    public List<DisciplineVM>? DisciplineS { get; set; }
}
public class DisciplineVM
{
    public string Subject { get; set; } = string.Empty;
    public int HoursLecture { get; set; }
    public int HoursPractice { get; set; }
    public string TypeOfControl { get; set; } = string.Empty;
}

И для VM классы Model:

public class SyllabusModel
    {
        public string TitleSyllabus { get; set; } = string.Empty;
        public List<SemestrModel>? Semesters { get; set; }
    }
    
    public class SemestrModel
    {
        public int Number { get; set; }
        public List<DisciplineModel>? DisciplineS { get; set; }
    }
    
    public class DisciplineModel
    {
        public string Subject { get; set; } = string.Empty;
        public int HoursLecture { get; set; }
        public int HoursPractice { get; set; }
        public string TypeOfControl { get; set; } = string.Empty;
    }

Мне нужно будет управлять списками внутри каждой вложенности (добавлять, удалять и изменять), а также сериализовать и десериализовать для этого правильно ли я понимаю что надо:

  1. В выше описанных VM я не создаю команды и логику по управлению списками и сериализацией\десериализацией, а создаю отдельную ViewModel в которой имеется бизнес логика над VM описанных выше - т.е. обертка.

Пример:

public class SyllabusViewModel : ReactiveObject
{
    public ReactiveCommand<Unit,Unit> CreateSyllabucCommand { get; set; }
    public ReactiveCommand<Unit,Unit> EditSyllabucCommand { get; set; }
    public ReactiveCommand<Unit,Unit> DeleteSyllabucCommand { get; set; }

    public ObservableCollection<SyllabusVM> Curriculum { get; set; }

    public SyllabusViewModel()
    {
        Curriculum = new ObservableCollection<SyllabusVM>();

    //МАПИНГ
        foreach (var syllabus in serviceData.GetDataSyllabus()) 
            Curriculum.Add(syllabus);
    //МАПИНГ

        CreateSyllabucCommand = ReactiveCommand.Create(CreateSyllabus);
        EditSyllabucCommand = ReactiveCommand.Create(EditeSyllabus);
        DeleteSyllabucCommand = ReactiveCommand.Create(DeleteSyllabus);
    }

    void CreateSyllabus() { }
    void EditeSyllabus() { }
    void DeleteSyllabus() { }
}

И такие ViewModel - обертки для каждой VM описанной выше. Нужны ли эти обертки или эта логика должна быть в VM описанных выше???

  1. Как правильно сериализовать такую вложенность. Зайти через верхний уровень и пройтись по каждой вложенностb через foreach-foreach-foreach и замапить типы VM в Model и сериализовать. Или же каждый слой сам должен делать мапинг. Или же может что-то другое дайте понимание сериализации вложенности с мапингом если он нужен)).

  2. Каждый учебный план представляет собой Json файл, который в сервисе засовывается в ICollection, мапиться в SyllabusVM и возвращается в public ObservableCollection<SyllabusVM> Curriculum { get; set; }.

Нужен ли такой мапинг в каждой прослойке для своего списка или же мапинг должен быть только на самом верхнем уровне вложенности пройдя по всей вложенностями несколькими циклами foreach-foreach-foreach???

Подскажите, пожалуйста)))


Ответы (1 шт):

Автор решения: Yaroslav

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


для VM классы Model

Не модели существуют для представлений, а представления для моделей. И когда пишут для это указывает на отношение одного к другому, но у тебя *VM никак ни к чему не относится, это просто тупо бесталковый клоны *Model, хотя должен быть его обёрткой.


ViewModel - обертки для VM

Извиняюсь за не скромный вопрос, а VM это не сокращение ViewModel? Взаимодействовать с одним или набором нескольких ViewModel, задача View!


Тут нет такого понятия как вложенность, это не разметка, не может один объект (например дисциплина) быть вложен в несколько других (семестры), на него могут только ссылаться объект (несколько семестров ссылаются на одну и ту-же дисциплину). Это называется отношения/связь (eng:relation), а базы данных с связанными данными, называются реляционными (Relational).


Какую функцию у тебя выполняет ViewModel? ViewModel это обёртка над Model. Например, если в Model есть url изображения, то в ViewModel может находиться загруженный по этой ссылке byte[] изображения, что бы его можно было отобразить в View. Одна ViewModel может и вовсе быть продуктом сразу нескольких Model. ViewModel это только посредник, не содержащий значимых данных, в нём нечего сериализовывать и в теме сохраниния данных он не участвует, от слова "ваще".


Ты столкнулся с проблемой, что если на дисциплину ссылаются несколько семестров, то при сериализации/десиаризации, семестры начинают ссылаться на разные копии одной и той-же дисциплины, потому что не сохраняются отношения между ними, только структура и значения.

Как Model не знает о существовании View, который её отображает, так он не должен знать о существовании сохранении/загрузки. Сохранение/загрузка это логика, которую всегда описывают отдельно, она не находится ни в модели, ни в представлении, ни в чём, она сама по себе. Как ViewModel посредник для View, так-же может быть посредник для хранения данных.

public class Discipline
{
    public string Name { get; set; } = string.Empty;
    ...
}
public class Semestr
{
    public int Number { get; set; }
    [JsonIgnore]
    public List<Discipline> Disciplines { get; set; }
}
public class SemestrData
{
    public Semestr Semestr { get; set; }
    public IEnumerable<string> DisciplineNames { get; set; }

    public SemestrData (Semestr semestr)
    {
        Semestr = semestr;
        DisciplineNames = Semestr.Disciplines.Select(s => s.Name);
    }
}

SemestrData легко сериализуется в Json не имея никаких ссылок, а только имена дисциплин.

public class LernData
{
    public SyllabusData SyllabuData { get; set; }
    public IEnumerable<SemestrData> SemestrData { get; set; }
    public IEnumerable<Discipline> Disciplines { get; set; }
}

Сам LernData сериализуется в Json и является контейнером набора взаимозависимых данных, сохраняющего целостность.

public void LinkData (LernData data)
{
    LinkSyllabusWithSemestrs(data.SyllabuData, data.SemestrData);
    LinkSemestrsWithDisciplines(data.SemestrData, data.Disciplines);
}

private void LinkSemestrsWithDisciplines (IEnumerable<SemestrData> semestrDatam, IEnumerable<Discipline> disciplines)
{
    Dictionary<string, Discipline> dDisciplines = disciplines.ToDictionary(d => d.Name);
    foreach (var data in semestrData)
    {
        List<Discipline> sDisciplines = new List<Discipline>();
        foreach (string name in data.DisciplineNames)
            sDisciplines.Add(dDisciplines[name]);
        data.Semestr.Disciplines = sDisciplines;
    }
}

Нужен только класс, которому скармливаешь план, семестры и дисциплины для дальнейшей упаковки в обёртки и контейнер LernData и его сериализации, а так-же десириализации с дальнейшим восстановлением связей между сущьностями по данным в обёртке.

→ Ссылка