Шаблон сховища - Як його зрозуміти і як він працює зі “складними” сутностями?


77

Мені важко зрозуміти шаблон сховища.

Є багато думок на цю тему, як у шаблоні репозиторію, зробленому правильно, але також інші речі, такі як репозиторій - це новий синглтон або знову, як у випадку не використовувати DAO використовувати репозиторій або просто взяти Spring JPA Data + Hibernate + MySQL + MAVEN, де-небудь сховище схоже на об'єкт DAO.

Мені набридло читати ці речі, оскільки це не може бути такою важкою справою, як це показано у багатьох статтях.

Я бачу це так: Здається, що я хочу, це приблизно так:

         ------------------------------------------------------------------------
         |                            Server                                    |
         ------------------------------------------------------------------------
         |                    |                        |                        |
Client <-|-> Service Layer  <-|->  Repository Layer  <-|-> ORM / Database Layer |
         |                    |                        |                        |  
         ------------------------------------------------------------------------

Service LayerПриймають *DTOоб'єкти і передає ті , в Repository Layerякі в основному не більше ніж «хлопець» , який знає , як юридична особа може бути збережено.

Наприклад, припустимо, що у вас є склад деяких інструментів ( зверніть увагу, що це просто псевдокод )

@Entity
class ToolSet {
  @Id
  public Long id;
  @OneToOne
  public Tool tool1;
  @OneToOne
  public Tool tool2;
}

@Entity
class Tool {
  @Id
  public Long id;
  @OneToMany
  public ToolDescription toolDescription;
}

@Entity
class ToolDescription {
  @Id
  public Long id;
  @NotNull
  @OneToOne
  public Language language

  public String name;
  public String details;
}

Річ, яку я не отримую, це частина, де я отримую ToolSetDTOоб’єкт від клієнта.

Наскільки я це зрозумів, я міг написати ToolSetRepositorya методом, ToolSetRepository.save(ToolSetDTO toolSetDto)який " знає, як зберігати " a ToolSetDTO. Але майже кожен підручник не проходить, *DTOа Entityзамість цього.

Мене тут турбує те, що якщо ви візьмете мій ToolSetприклад згори, мені доведеться виконати такі дії:

  1. Візьміть toolSetDtoі перевірте, якщо ніnull
  2. Для кожного, що tool*Dtoналежить toolSetDto
    а) Якщо має дійсний ідентифікатор, перетворіть з, DTOщоб Entityінакше створити новий запис бази даних
    b) toolDescriptionDtoта перетворіть / збережіть його в базі даних або створіть новий запис
  3. Після перевірки наведених вище примірників ToolSet(сутності) та налаштування для збереження у базі даних

Все це занадто складно, щоб просто дозволити службовій функції (інтерфейс для клієнта) обробляти це.

Я думав про те, щоб створити, наприклад, ToolSetRepositoryале, але питання тут

  • Це бере об'єкт ToolSetсутності або використовує DTOоб'єкт?
  • У будь-якому випадку: чи *Repositoryдозволено використовувати інші об’єкти сховища? Як коли я хочу заощадити, ToolSetале я маю зберігати, Toolі ToolDescriptionспочатку - чи скористаюся я ToolRepositoryі ToolDescriptionRepositoryвсередині ToolSetRepository?
    Якщо так: чому це не порушує шаблон сховища? Якщо цей шаблон є в основному шаром між службою та моєю структурою ORM, він просто не "почувається правильно" додавати залежності до інших *Repositoryкласів через причини залежності.

Я не знаю, чому я не можу розібратися з цим. Це не здається , що складно , але там все ще допомогти там , як Spring Data. Інша справа, яка мене турбує, оскільки я справді не розумію, як це робить щось простіше. Тим більше, що я вже використовую Hibernate - я не бачу користі (але, можливо, це вже інше питання).

Отже .. Я знаю, що це довге питання, але я вже кілька днів досліджував його. Вже існує код, над яким я зараз працюю, який починає перетворюватися на безлад, бо я просто не бачу цього шаблону.

Я сподіваюся, хтось може дати мені загальну картину, ніж більшість статей та навчальних посібників, які не виходять за рамки реалізації дуже, дуже простого прикладу шаблону сховища.


на мій погляд ToolSetRepository повинен знати лише сутність ToolSet ... а на ToolSet ви також можете мати анотації JaxB, щоб використовувати сутність як DTO. на стороні клієнта у вас є лише класи jaxb, згенеровані за допомогою clientgen jaxws з wsdl, отриманого з URL-адреси веб-служби плюс "? wsdl" .... на стороні сервера, тоді ви отримуєте "некерований" об'єкт. тоді вам потрібно використовувати entitymanager.merge, щоб перевести його в керований стан. це все. на мій погляд, конкретне сховище потрібне лише для складних критеріїв, де ви не можете використовувати іменовані запити. наприклад, критерії api-запитів.
StefanHeimberg

@StefanHeimberg Але як, ToolSetRepositoryнаприклад, можна впоратись із наполегливістю Toolта ToolDescription? З тих, що вже мали бути наполегливими? Якби їх слід було зберегти на цьому етапі, то де б я це зробив? Робити це всередині мого методу служби не здається правильним, оскільки складні сутності, як ToolSetби, здули код методу служби. Імхо, що службовий метод повинен виконати кілька ініціалізацій та базових перевірок, а потім делегувати роботу наступному шару.
Стефан Фальк

якщо ви отримуєте "некеровану" сутність на рівні обслуговування (межа транзакції), а потім використовуєте злиття () на диспетчері сутності, тоді сутність вже знайома з управління суттю. після завершення методу обслуговування транзакція здійснюється, а зміни в менеджері сутності зберігаються в базі даних ...
StefanHeimberg

1
AFAIK Hibernate (і JPA) - це цілий рівень DAO, оскільки його робота полягає в підключенні до джерела даних (у даному випадку бази даних), незважаючи на основні деталі (MySQL, Oracle, SQL Server тощо), і ви можете запитувати джерело даних різними способами . Якщо ви хочете / потребуєте використовувати конкретні запити для своїх сутностей, це дозволяє використовувати критерії, які вказані для використання у сховищі, тож врешті-решт Hibernate є і Dao, і сховищем. Все, що ви будете робити поверх цього, - це створення власного шару для абстрагування цього дао (або сховища) або будь-чого іншого, що ви використовуєте для його реалізації та продовження програмування.
Луїджі Мендоса

2
merge () вже перевіряє, чи є новий чи ні. а потім створіть запит на вставку або оновлення. на мій погляд, це відповідальність основного ORM. наприклад, JPA.
StefanHeimberg

Відповіді:


114

Ви можете прочитати мій пост "сховище для чайників", щоб зрозуміти простий принцип роботи сховища. Я думаю, ваша проблема в тому, що ви працюєте з DTO, і в цьому випадку ви насправді не використовуєте шаблон сховища, ви використовуєте DAO.

Основна відмінність сховища від дао полягає в тому, що сховище повертає лише ті об’єкти , які розуміє викличний рівень . Здебільшого сховище використовується бізнес-рівнем і, таким чином, воно повертає бізнес-об’єкти. Дао повертає дані, які можуть бути або не бути цілим бізнес-об’єктом, тобто дані не є дійсною концепцією бізнесу.

Якщо ваші бізнес-об’єкти - це лише структури даних, це може бути натяком на вашу проблему з моделюванням, тобто поганий дизайн. Сховище має більше сенсу для "багатих" або, принаймні, належним чином інкапсульованих об'єктів. Якщо ви просто завантажуєте / зберігаєте структури даних, ймовірно, вам не потрібне сховище, цього достатньо.

Якщо ви маєте справу з бізнес-об'єктами, які складаються з інших об'єктів (сукупність), і цьому об'єкту потрібні всі його частини, щоб бути послідовним (сукупний корінь), тоді шаблон сховища є найкращим рішенням, оскільки він абстрагує всі деталі збереження . Ваш додаток просто запитає "Продукт", і сховище поверне його в цілому, незалежно від того, скільки таблиць або запитів потрібно для відновлення об'єкта.

Виходячи з прикладу коду, у вас немає «справжніх» бізнес-об’єктів. У вас є структури даних, які використовує Hibernate. Бізнес-об’єкт розробляється на основі бізнес-концепцій та випадків використання. Сховище дозволяє BL не піклуватися про те, як зберігається цей об'єкт. Певним чином, сховище діє як 'перетворювач / перетворювач' між об'єктом та моделлю, яка буде зберігатися. В основному репо "зводить" об'єкти до необхідних для збереження даних.

Бізнес-об'єкт не є організацією ORM. Це може бути з технічної точки зору, але з дизайнерського поверху один моделює бізнес, а інші моделює наполегливість. У багатьох випадках вони не є безпосередньо сумісними.

Найбільша помилка - це проектувати свій бізнес-об’єкт відповідно до потреб у сховищі та мислення. І на відміну від того, що вважають багато розробників, мета ORM - не зберігати бізнес-об'єкти. Його мета - імітувати базу даних "oop" поверх rdbms. Зіставлення ORM знаходиться між вашими db-об'єктами та таблицями, а не між об'єктами додатків (ще менше при роботі з бізнес-об'єктами) та таблицями.


1
Привіт! Зараз мені набагато зрозуміліше, що таке сховище, але я хотів би запитати свій конкретний приклад коду, якщо зможу: Річ у тому, що на моєму клієнтському боці не так багато відбувається, тому ніколи не буде набагато більше робити, ніж в основному зберігати, наприклад, ToolSetу базі даних. Але це все ще не означає, що я можу писати, ToolSetRepositoryщо в основному створює мій клас сутності, а потім зберігає його, чи правильно? І останнє велике питання, яке я отримав у своєму запитанні, - " У будь-якому випадку: чи *Repositoryдозволено використовувати інші об'єкти сховища (всередині нього)? ".
Stefan Falk

1
Жоден з підручників, які я бачив, не показав більш складного прикладу, коли сховище насправді має робити те, що люди стверджують, що воно існує. Я бачу лише жорстоко простий приклад, який змушує мене замислюватися, для чого мені це знадобиться? ^^ За винятком того, що дозволено використовувати інші об'єкти сховища в інших об'єктах сховища, щоб виконати роботу. :)
Стефан Фальк

4
@StefanFalk Шаблон сховища насправді є дизайном інтерфейсу . Отримавши інтерфейс, ви можете здивуватись фактичною реалізацією. Щодо сховища, яке використовує інші сховища, я думаю, ні, це неправильний дизайн, це означало б, що у вас є 2 репозиторії, що мають справу з одними і тими ж об’єктами. Але сховище може використовувати багато DAO. У моїй кодовій базі репозиторії не знають один про одного. Справа в тому, що для правильного використання сховища потрібно мати належну бізнес-модель (з чіткими межами узгодженості), інакше це просто ускладнення.
MikeSW

3
До речі, метою сховища є зберігання / отримання матеріалів. Чим складніші речі, тим вони кращі. Але пам’ятайте важливий біт: цей об’єкт повинен представляти бізнес- концепцію або просту (одна структура), або складну (багато правил або багато дітей).
MikeSW

1
Ні! Сховище - це лише проблема постійності. Ніколи не вкладайте в нього такі речі, як http. Ви порушуєте принцип розділення турбот. Ви дійсно хочете мати один об’єкт, який робить все? Реалізація репо завжди є частиною постійності (як концепція), ваш додаток повинен використовувати лише абстракцію за допомогою ін'єкції, тобто контейнер di повинен створювати репо, яке повинно ТІЛЬКИ зберігати / завантажувати з db, не перевіряючи безпеку. Ви можете "перевірити" речі, якщо вони є частиною запиту, наприклад "вибрати * з інструментів, де id = @ 0 та userId = @ 1".
MikeSW
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.