Где получить доступ к настойчивости в DDD - PullRequest
1 голос
/ 29 мая 2020

Я изучаю дизайн, управляемый доменами (да, я довольно опаздываю на эту вечеринку), и до сих пор я пришел к осознанию того, что модель домена должна быть центром вселенной. Сохранение данных - это просто практическая деталь.

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

Например, если я хочу быть может добавить новую оценку студенту, следует ли мне вызвать репозиторий из модели предметной области студента, например:

interface IGradeRepository
{
    void SaveGrade(int courseId, string grade);
    // ...other methods
}

class Student
{
    IGradeRepository _gradeRepository;
    List<Grade> _grades = new List<Grade>();

    public Student(IGradeRepository gradeRepository) 
    {
        _gradeRepository = gradeRepository;
    }

    int StudentId { get; set; }

    void AddGrade(int courseId, string grade)
    {
        var grade = new Grade(this.StudentId, courseId, grade);
        _grades.Add(grade);

        // Do I put the call to the data persistance here?
        _gradeRepository.SaveGrade(grade);
    }
}

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

Итак, подведем итог: откуда я могу получить доступ к уровню данных при проектировании, управляемом доменом?

Обновление

Как отмечают некоторые, из моего примера не ясно, как я могу получить доступ к классу учеников. Я бы, вероятно, сделал это из модели представления или через какую-то службу вариантов использования.

Пример с представлением модели:

class StudentGradesViewModel
{
    // (...) all sort of VM-stuff

    private Student _student;
    private Course _selectedCourse;

    public void AddGrade(string grade)
    {
        _student.AddGrade(_course.CourseId, grade);
    }
}

Ответы [ 3 ]

2 голосов
/ 02 июня 2020

Прежде всего: репозиторий должен относиться только к агрегату. В вашем случае у вас есть ученик, который может иметь несколько оценок. Итак, ваш репозиторий всегда должен быть постоянным для агрегата, а не сущностью внутри агрегата.

Вот решение, которое я бы выбрал:

Агрегат на уровне домена:

class Student
{
    List<Grade> _grades = new List<Grade>();
    int StudentId { get; set; }

    public Student() 
    {
    }

    void AddGrade(int courseId, string grade)
    {
        var grade = new Grade(this.StudentId, courseId, grade);
        _grades.Add(grade);
    }
}

Интерфейс репозитория на уровне домена:

interface IStudentRepository
{
    void SaveStudent(int studentId);
    // ...other methods
}

Конечно, как было упомянуто в сообщениях выше, реализация репозитория должна происходить на уровне инфраструктуры.

Вы должен создать Application Service или CommandHandler (если вы используете CQRS), чтобы интегрировать logi c домена и инфраструктуру:

class AddGradeService
{    
    private readonly IStudentRepository _studentRepository;

    public AddGradeService(IStudentRepository studentRepository) 
    {
        _studentRepository = studentRepository;
    }

    void Handle(int studentId, int courseId, string grade)
    {
        Student student = _studentRepository.Get(studentId);
        student.AddGrade(courseId, grade);
        _studentRepository.Save(student);
    }
}

Вот как это должно быть сделано :) Вы также можете обратиться к моему пример od DDD, если хотите: https://github.com/czarek-szok/DDD.Ecommerce/

0 голосов
/ 29 мая 2020

Лучшее время присоединиться к группе - прямо сейчас, так что не беспокойтесь. Вы должны не получать доступ к сохранению данных непосредственно из вашей модели предметной области, вместо этого это следует делать на уровне инфраструктуры. Если вы знакомы с Onion Architecture, она прекрасно это объясняет. Вы можете найти его здесь или здесь . Те же принципы, которые описаны в ссылках, могут быть применены к вашему случаю.

Доступ к уровню сохраняемости (обычно именуемой инфраструктурой) осуществляется через выполнение ваших сценариев использования, которые обычно размещаются на уровне приложения и реализуются с помощью команд (управление состояние сущностей) или запросы (чтение состояния постоянных сущностей)

0 голосов
/ 29 мая 2020

следует ли мне вызывать репозиторий изнутри модели предметной области студента, как это?

Это не обычный шаблон.

Вместо этого чаще встречается взаимодействие с репозиториями происходит на уровне приложения, а не на уровне домена.

Репозитории предоставляют приложению доступ к агрегату root, и приложение взаимодействует только с агрегатом root. Таким образом, простой шаблон выглядит примерно так:

using transaction():
    Root root = _repository.get(rootId)
    root.doSomeCoolDomainThing(...)

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

В некоторых случаях вы увидите, что сохранение root в репозиторий делается более явным:

using transaction():
    Root root = _repository.get(rootId)
    root.doSomeCoolDomainThing(...)
    _repository.save(root)

Что такое root, когда вы дойдете до самого дна?

Root - это объект модели предметной области ; это тот, который, так сказать, «отвечает» за все остальные объекты в этом конкретном агрегате.

Здесь я просто использую его как подставку. В реальном проекте орфография будет отражать язык вашего домена - Student, GradeBook, ReportCard и т. д. c.

...