Сопоставление модели предметной области с базой данных с помощью EF Fluent API

Ниже представлен класс code-first Project, напрямую сопоставленный с базой данных через Entity Framework 6 Fluent API:

public class Project
{
    public Project()
    {}

    public int ProjectId { get; set; }

    public string Name { get; set; }

    public bool IsActive { get; set; }

    public ICollection<ProjectVersion> ProjectVersions { get; set; }
}

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

Вот как Project будет выглядеть как класс модели предметной области:

public class Project
{
    private readonly List<ProjectVersion> projectVersions;

    public Project(string name, string description)
    {
        Name = name;
        Description = description;
        projectVersions = new List<ProjectVersion>();
    }

    public int ProjectId { get; private set; }

    public string Name { get; set; }

    public bool IsActive { get; private set; }

    public IEnumerable<ProjectVersion> ProjectVersions 
    { 
        get
        {
            return projectVersions;
        }
    }

    public void AddVersion(ProjectVersion version)
    {
        projectVersions.Add(version);
    }
}

Из того, что я прочитал , я могу сопоставить частные поля с помощью Fluent API EF.

Есть ли здесь недостатки? Я иду по ненужному пути?

Единственная проблема, которую я могу предвидеть, — это когда модель бизнес-домена по существу будет состоять из данных из двух или более объектов данных.




Ответы (2)


Я думаю, что вы делаете ошибку в этом подходе. Я думаю, вы должны отделить проблемы ваших моделей предметной области от проблем ваших моделей сущностей. Дядя Боб написал странную, но точную запись в блоге об этом здесь: Dance You Imps! (серьезно, это странный пост.) Работа ORM заключается в том, чтобы действовать как контракт с вашей базой данных. Работа ваших моделей предметной области заключается в обеспечении функциональности. Короче говоря, вы должны позволить Entity Framework функционировать так, как он этого хочет. Если вы хотите использовать DDD, напишите слой сопоставления для преобразования моделей EF в модели домена.

person Chris McKenzie    schedule 13.12.2013
comment
Ну, со статьей не поспоришь. Однако я могу заявить, что если вы раскрываете свои свойства и намерены использовать модель, которая сопоставляется с базой данных, то я не вижу причин не просто сопоставлять свойства ваших объектов предметной области с хранилищем данных. Однако приведенный выше пример не будет работать, если EF6 теперь не может обрабатывать конструкторы с параметрами. - person VeteranCoder; 11.03.2014

Есть ли здесь недостатки?

Возможно.

Это правда, что EF может обращаться к закрытым членам, поэтому он может материализовать Project с загруженной коллекцией ProjectVersions, если вы хотите. Он не будет использовать для этого метод AddVersion (он даже не знает о его существовании), но добавит объекты к члену projectVersions.

В код приложения вы хотите добавить версии через метод. Однако с этим методом AddVersion могут возникнуть некоторые проблемы.

  • Вы всегда можете добавить ProjectVersion, но вы никогда не будете уверены, будет ли он сохранен, потому что для отслеживания EF добавление projectVersions должно быть загружено. Однако вы не хотите, чтобы объект домена отвечал за загрузку своих дочерних элементов из базы данных. Таким образом, AddVersion возлагает на класс ответственность, которую он не может выполнить в полной мере.
  • Вызов AddVersion может произойти в любой момент жизни объекта. Обычно это будет дольше, чем срок службы контекста, в котором он был создан и отслежен. Таким образом, вы не можете полагаться на ленивую загрузку, чтобы прийти на помощь, если коллекция еще не загружена. (кстати, ProjectVersions должен virtual ICollection за это).
  • Вывод таков, что вы всегда должны загружать projectVersions с нетерпением (через Include), чтобы AddVersion гарантированно работало должным образом. Таким образом, в вашем приложении существует зависимость между двумя явно не связанными фрагментами кода, что является потенциальным источником ошибок.
  • Когда пришло время сохранить Project, вы должны прикрепить его к контексту и выяснить, какие ProjectVersion должны быть помечены для вставки, а какие для обновления (а пока нет даже метода RemoveVersion.

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

person Gert Arnold    schedule 13.12.2013