Сопоставление постоянной модели с моделью домена без раскрытия атрибутов объекта домена

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

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

@Entity
class SomeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String attribute1;
    private String attribute2;
    private String attribute3;
    // ... other attributes

    protected SomeEntity() {}

    /* Public getters */
    public Long getId() { ... }

    public String getAttribute1() { ... }

    public String getAttribute2() {  ... }

    /* Expose some behaviour */
    public void updateAttributes(String attribute1, String attribute2) { 
       /* do some validations before updating */
    }
}

Моя проблема возникает, если я хочу иметь другую постоянную модель. Тогда у меня было бы что-то вроде:

/* SomeEntity without persistent info */
class SomeEntity {
    private Long id;
    private String attribute1;
    private String attribute2;
    private String attribute3;
    // ... other attributes

    protected SomeEntity() {}

    /* Public getters */
    public Long getId() { ... }

    public String getAttribute1() { ... }

    public String getAttribute2() {  ... }

    /* Expose some behaviour */
    public void updateAttributes(String attribute1, String attribute2) { 
       /* do some validations before updating */
    }
}

и ДАО:

@Entity
class SomeEntityDAO {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String attribute1;
    private String attribute2;
    private String attribute3;

    public SomeEntityDAO() {}

    /* All getters and setters */
}

Мой вопрос: как я могу сопоставить SomeEntityDAO с SomeEntity, не раскрывая атрибуты SomeEntity?

Если я создам такой конструктор, как: public SomeEntity(String attribute1, String attribute2, ...) {}, то любой может создать недопустимый экземпляр SomeEntity. То же самое произойдет, если я сделаю все сеттеры общедоступными в SomeEntity.

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

Я думаю о защите всех сеттеров, чтобы DAO мог расширить Entity и иметь доступ к сеттерам... но я не уверен, что это хороший вариант.

Каков наилучший или распространенный подход к решению этой проблемы?


person Tobías    schedule 11.10.2017    source источник
comment
Вы хотели бы ORM, который позволяет классам сущностей не иметь сеттеров или иметь частные сеттеры?   -  person Jeff Miller    schedule 13.10.2017
comment
Я имею в виду классы модели предметной области без раскрытия общедоступных сеттеров. Выставление только методов поведения. Геттеры в порядке. А классы ORM могут иметь геттеры и геттеры.   -  person Tobías    schedule 14.10.2017


Ответы (3)


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

Учитывая это, я пришел к выводу, что если вы действительно хотите сохранить чистоту своих доменных объектов (так что не получайте и не устанавливайте - последнее я бы НИКОГДА не принял!), Вы должны заключить некоторые сделки. Потому что невозможно поделиться внутренними компонентами, не дав сущностям дополнительные знания. Осторожно, это не означает, что вы должны сообщать объектам домена об уровне ORM или использовать геттеры. Просто я пришел к выводу, что объекты домена должны иметь способы представить их как другую модель.

Итак, в заключение, что бы я сделал в вашей ситуации, так это создал шаблон посетителя. Сущность домена EntityA должна реализовать интерфейс EntityAVisitable для приема EntityAVisitor или чего-то подобного.

interface EntityAVisitable {
   accepts(EntityAVisitor visitor);
}

Построитель реализует интерфейс, необходимый посетителю, EntityAVisitor.

interface EntityAVisitor<T>{
    setCombinedValue1_2(String attribute1_attribute2_combinedInEntity);
    <T> build();
}

Функция build() интерфейса EntityAVisitor использует общий тип T. Таким образом, объект домена не зависит от возвращаемого типа конкретной реализации EntityAVIsitor.

Это идеально? Нет.

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

Это мило? Нет.

Хорошее решение не допускается из-за языковых ограничений (полагаю, вы используете Java).

Хорошо ли это работает при инкапсуляции реального содержимого вашего объекта домена? Да.

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

person Luca Masera    schedule 12.10.2017

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

Используйте объекты домена при изменении и DTO для проекций только для чтения. При использовании прямых DTO в режиме только для чтения вы получаете выигрыш в производительности и упрощении. Это используется в шаблонах CQRS.

class SomeEntity {
    private Long id;
    private String attribute1;
    private String attribute2;
    private String attribute3;
    // ... other attributes

    public SomeEntity() {}

    /* Public getters/setter */
    public Long getId() { ... }

    public String getAttribute1() { ... }

    public String getAttribute2() {  ... }

    public Long setId() { ... }

    public String setAttribute1() { ... }

    public String setAttribute2() {  ... }
}

//classes/interfaces named for clarity
class EntityUpdater implements IEntityUpdater {
  public EntityUpdater (ISpecification spec){
  }

  public updateEntity(SomeEntity entity){
    //assert/execute validation
  }
}
person alltej    schedule 11.10.2017

Некоторые ORM позволяют устанавливать значения сущностей через доступ к полям (в отличие от методов установки).

JPA использует аннотацию @Access. См. Какова цель AccessType.FIELD, AccessType.PROPERTY и @Access

Я создал ORM, sormula, который может использовать доступ к полям. См. @Row fieldAccess и тестовый пример org. .sormula.tests.fieldaccess.

person Jeff Miller    schedule 16.10.2017