Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.86/7: Рейтинг темы: голосов - 7, средняя оценка - 4.86
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54

Архитектура приложения: разделение кода на слои

22.09.2023, 22:33. Показов 1845. Ответов 34
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!

Подскажите, пожалуйста, по разделению кода программы на слои.

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

Общий алгоритм следующий:
1) Выгружаем из конкретной n-ой базы-источника товары в файл передачи - это делает отдельная утилита.
2) Запускаем нашу программу, в ней выбираем файл передачи (загрузки).
3) Читаем старые товары из файла загрузки, создаем таблицу этих товаров (в памяти) - ТЗ-БД-Источник, и делаем некоторые преобразования.
4) Читает товары из новой базы также в таблицу в памяти ТЗ-БД-Новая, делаем некоторые преобразования.
Преобразования в пунктах (3) и (4) нужны для того, чтобы значения полей товаров из разных баз можно было сопоставить друг с другом.
5) Читаем из базы флажки (см. далее) для товаров из базы-источника. Флажки обозначают состояние товара из базы-источника (загружен он уже или еще нет) и что с ним надо делать (надо загружать или нет). Подробнее назначение флажков описано далее.
6) По разным реквизитам (наименование, штрихкод) выполняем поиск соответствия между товарами из текущей базы и из базы-источника (по таблицам ТЗ-БД-Источник, ТЗ-БД-Новая).
Это соответствие между товарами пока что "логическое".
Результат соответствия, а также флажки, помещаем в специальную таблицу в памяти ТЗ-Соответствие, которую можно представить в виде дерева. Каждый "узел" дерева - это совпадающие реквизиты товаров. Подчиненные строки "узла" этого дерева: первая строка - это товар из источника, вторая строка - это товар в новой базе.
7) В таблице-дереве добавляем специальные колонки для флажков-признаков "проверен", "записывать", "записан" (при первом заполнении они пустые).
Пользователь может вкл.\выкл. эти флажки. Значения флажков при переключении должны быть сохранены в базе.
Эти флажки обозначают, что надо делать с товаром из базы-источника.
8) Выводим пользователю эту таблицу-дерево с узлами соответствия и флажками.
9) Пользователь смотрит на эту таблицу, проверяет данные:
9.1) Если пользователь убеждается, что соответствие установлено верно и товар надо загружать, он включает флажки "проверено", "записывать".
При этом в базу записывается "жесткое" фиксированное соответствие: GUID товара из старой базы, GUID товара из новой базы, признак "записывать" = "Да".
9.2) Если пользователь убеждается, что соответствие установлено верно и товар не надо загружать, он включает признак "проверено", "записывать" выключает.
В базу записывается "жесткое" фиксированное соответствие: GUID товара из старой базы, GUID товара из новой базы, и признак "записывать" = "Нет".
9.3) Если соответствия нету, и пользователь решает, что товара из старой базы еще нету в новой базе, он включает признаки "проверено", "записывать".
Это значит, что в новой базе надо создать новый товар со сведениями товара из старой базы.
В базу записывается просто GUID товара из старой базы и признак "записывать" = "Да".
10) Пользователь нажимает кнопку "Записать".
Для каждой строки из списка выделенных строк:
— выполняется проверка флажков "проверен" и "записан", если флажки установлены, то выполняется:
— запись информации о товаре в базу
— запись в таблицу "Флажки" признака "записан" и GUID товара из старой базы, чтобы при повторной работе скрыть уже записанные товары.

Вопрос такой.
Как правильно разделить этот код на слои View - ViewModel - Model - Repository?

В соответствии с пунктами (3)-(6) в памяти надо иметь три таблицы:
- "линейная" таблица старых товаров
- "линейная" таблица новых товаров
- таблица-дерево соответствия старых и новых товаров.
По сути это некий "кэш" в памяти.

В каком слое программы должны быть эти таблицы? В бизнес-слое?
Получается, пользовательский слой должен работать только с таблицей-деревом?
Какая должна быть логика взаимодействия между слоями?

Например, как выполняется запись в базу товара по узлу соответствия?
Программа же должна "поддерживать" наш "кэш" в корректном состоянии.

Подскажите, пожалуйста.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
22.09.2023, 22:33
Ответы с готовыми решениями:

Разделение приложения на слои. Работа с шаблонными типами
Помогите пожалуйста, встал в ступор, вторую неделю не могу решить поставленную задачу. БД на MS SQL Server Работа с БД была реализованна...

Разделение кода extjs приложения
добрый день , подскажите плз , как привильно\можно разделить код extjs приложения, то читаемость кода уже почти нулевая, что хочу. есть...

В указанном dsn архитектура драйвера и архитектура приложения не соответствуют друг другу
Добрый день. При запуске программы выскакивает вот такая вот ошибка. В чем может быть проблема и как ее исправить?

34
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
26.09.2023, 16:31
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от zelenprog Посмотреть сообщение
В этой среде разработки для отображения таблицы записей на Форме, ничего не нужно делать, не нужно никакого маппинга.
Мне трудно давать советы не зная особенностей вашей среды обработки.
В WPF тоже можно использовать DataTable в GUI, но это неудобно. И используется только в крайних случаях когда по другому невозможно реализовать.

Опять таки, не зная вашей среды разработки я не могу подсказать насколько верным будет собирание Дерева из Таблиц на уровне View. Возможно в вашей среде это и вовсе невозможно.

Цитата Сообщение от zelenprog Посмотреть сообщение
Проблема в том, как "протащить" заполненную сырыми данными из Репозитория на Форму? Репозиторий ведь не доступен из Формы. Форма работает с Моделью.
Если в вашей среде ValueTable является комфортным и нормальным типом для GUI, то прокидывайте его через все слои.
DataTable поддерживает уведомления об изменении строк и ячеек, которые корректно автообнавляют WPF элементы.
Поэтому обновление DataTable в Репозитории не вызовет никаких проблем в WPF. Насколько верно это для вашей среды с ValueTable я тоже не могу сказать.
0
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54
26.09.2023, 17:25  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
DataTable поддерживает уведомления об изменении строк и ячеек, которые корректно автообнавляют WPF элементы.
Поэтому обновление DataTable в Репозитории не вызовет никаких проблем в WPF. Насколько верно это для вашей среды с ValueTable я тоже не могу сказать.
В нашей среде для ValueTable это тоже работает.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если в вашей среде ValueTable является комфортным и нормальным типом для GUI, то прокидывайте его через все слои.
Но ведь это нарушение всей архитектуры! В этом то и проблема.
Так-то можно вообще, используя Binding, привязать элемент формы к таблице из Репозитория. Но везде пишут, что это плохо.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
26.09.2023, 17:56
Цитата Сообщение от zelenprog Посмотреть сообщение
Так-то можно вообще, используя Binding, привязать элемент формы к таблице из Репозитория. Но везде пишут, что это плохо.
Это же зависит от многих условий.
Например, в "стандартном" WPF-Репозиторий более комфортным является работа с коллекциями сущностей представляющими записи таблиц (более верно парсинг запросов к БД). Но эти же сущности создаёт Репозиторий. Каким образом (EF, Реадер, DataTable) не суть важно.
В ваших условиях вам удобнее использовать ValueTable вместо коллекций. Но это же не противоречит функциям репозитория. ValueTable можно возвращать из Репозитория, так же как и DataTable.
0
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54
27.09.2023, 09:13  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В ваших условиях вам удобнее использовать ValueTable вместо коллекций. Но это же не противоречит функциям репозитория. ValueTable можно возвращать из Репозитория, так же как и DataTable.
Репозиторий может возвращать ValueTable.
А как эта ValueTable попадет в пользовательский интерфейс? Пользовательский интерфейс ведь не работает (не "общается") с Репозиторием.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
27.09.2023, 13:43
Цитата Сообщение от zelenprog Посмотреть сообщение
А как эта ValueTable попадет в пользовательский интерфейс? Пользовательский интерфейс ведь не работает (не "общается") с Репозиторием.
Прокинуть через Модель.

Добавлено через 7 минут
Я всё равно не совсем понимаю нюансов вашей среды.
Например, в "обычной реализации", в VM+View можно создаться сущность, отредактировать её, после этого послать в Модель, которая её сохранит через Репозиторий. Репозиторий обновит или пересоздаст сущность при сохранении и вернёт её. Если есть какие-то коллекции, то обновлённая сущность записывается во все где она используется. Это достаточно про и понятно для реализации и последующей поддержки.
В случае же DataTable, нужно передавать не сущность, а коллекцию данных либо в параметрах метода, либо через словарь. Репозиторий конвертирует их в Строку DataTable. И в такой реализации теряется самая основная "фишка" ООП - сам объект с которым по сути и идёт работа.

В вашем случае это так же происходит? И для вашей среды обработки это норм? Там не используется ООП?
0
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54
27.09.2023, 17:19  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Прокинуть через Модель.
А как это сделать?
Модель ведь может работать только с объектами бизнес-логики, то есть с сущностями и их коллекциями. Как сюда "втиснуть" ValueTable?
Может быть сделать какую-то обертку вокруг ValueTable? Модель будет думать, что это какая-то особенная коллекция.
А когда эта коллекция "дойдет" до ViewModel, то ViewModel попытается вызвать у этой коллекции метод типа "GetValueTable()".
Насколько такой способ нарушает принципы "правильного" дизайна и взаимодействия View-ViewModel-Model?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Я всё равно не совсем понимаю нюансов вашей среды.
Думаю, тут дело не в среде, а в сценарии работы.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Например, в "обычной реализации", в VM+View можно создаться сущность, отредактировать её, после этого послать в Модель, которая её сохранит через Репозиторий. Репозиторий обновит или пересоздаст сущность при сохранении и вернёт её.
Если есть какие-то коллекции, то обновлённая сущность записывается во все где она используется.
Насчет коллекций интересно...
Какой объект отвечает за обновление коллекций при изменении сущности? Репозиторий? Тогда ему придется "помнить" все коллекции. Так ведь?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
... в "обычной реализации", в VM+View можно создаться сущность, отредактировать её, после этого послать в Модель, которая её сохранит через Репозиторий. Репозиторий обновит или пересоздаст сущность при сохранении и вернёт её.
В этом примере вы описываете сценарий работы пользователя с одной сущностью.
VM+View умеет работать только с одной сущностью?
Разве нету каких-либо "специальных" View и ViewModel, которые умеют работать с коллекциями сущностей?

Представьте, если пользователю надо работать с таблицей сущностей. Тогда как будет выполняться этот сценарий для VM+View?
Как коллекция сущностей отобразится у пользователя? Как изменения, внесенные пользователем в эту таблицу, "дойдут" до Модели и будут там обработаны?
Как я понимаю, в "классическом" ООП для этого нужно делать двойное преобразование данных:
- первое выполняет Репозиторий: получает запросом RecordSet и делает из полученного RecordSet-а коллекцию,
- а второе преобразование делает ViewModel, когда из коллекции заполняет таблицу на форме.
Так?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
В случае же DataTable, нужно передавать не сущность, а коллекцию данных ....
Как я понимаю, типы данных подобные DataTable есть во многих средах разработки, и они были специально созданы для удобной работы с несколькими однотипными записями с одинаковым набором полей.
Это множество записей можно назвать как угодно - коллекция, таблица записей, набор записей, массив записей, таблица значений - это не принципиально.
Важно то, что DataTable позволяет очень легко показать их пользователю в табличном виде, не выполняя маппинга туда-сюда.
В принципе, этот тип может быть использован как основа для реализация коллекции.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Репозиторий конвертирует их в Строку DataTable.
Наверно вы имели ввиду "Репозиторий конвертирует их в Строки DataTable"?
Один объект - одна строка DataTable.
Для Репозитории эта конвертация очень простая. Он ведь скорее всего получает результаты запросов в виде похожем на DataTable, что-то типа RecordSet.
Надо просто пройтись по всем строкам RecordSet-а, и каждую запись один-в-один записать в DataTable.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
И в такой реализации теряется самая основная "фишка" ООП - сам объект с которым по сути и идёт работа.
При необходимости работать с объектом, его всегда можно получить из строки DataTable.
Для "обычной" работы Модели Репозиторий по прежнему может возвращать или Сущность или Коллекцию сущностей. Ясно, что какие-то бизнес-правила могут быть реализованы только для объекта.
"Классическая" Модель не должна работать с записями DataTable. Она должна получить объект из строки DataTable (пока не понятно как), и затем работать с объектом.

А вот для особенных случаев, для оптимизации, когда нужно просто отобразить таблицу данных пользователю можно использовать DataTable.
Получается, что DataTable может быть использвана в "одностороннем" порядке - при отображении.

Также у меня крутится мысль: а может быть сделать отдельный Репозиторий для работы с DataTable?
Модель будет знать, что один Репозиторий - это настоящий для базы данных, а второй - это для временного хранения то есть для DataTable. И модель будет манипулировать ими по необходимости. Надо получить объект из БД - Модель запрашивает Репозиторий-1, надо получить объект из строки DataTable - запрашивает Репозиторий-2.
Модель ведь может работать с любым количеством Репозиториев?

Но это все мои рассуждения. Как делать правильно - я не знаю
В общем получается такая картина. Во многих средах разработки есть что-то типа DataGridView + DataTable, а также binding. Это очень удобно, производительно.
Но это не вписывается в "классический" ООП, DDD, MVVM. Как это совместить?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
27.09.2023, 18:49
Цитата Сообщение от zelenprog Посмотреть сообщение
Как я понимаю, типы данных подобные DataTable есть во многих средах разработки, и они были специально созданы для удобной работы с несколькими однотипными записями с одинаковым набором полей.
Неа...
Они были созданы тогда когда ещё были слабые нормальные инструменты ООП для такой работы.
Сейчас всё это считается "древним хламом" и используется только в каких-то уникальных заданиях.

Цитата Сообщение от zelenprog Посмотреть сообщение
Насчет коллекций интересно...
Какой объект отвечает за обновление коллекций при изменении сущности? Репозиторий? Тогда ему придется "помнить" все коллекции. Так ведь?
По разному.
Как выше описывал, например, в EF есть возможность получить локальный кеш таблицы, связать его с ObservableCollection и вернуть её. В таком сценарии View может использовать коллекцию, которую создал и контролирует Репозиторий.

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

И есть куча ещё других вариантов реализации в которых работают и с коллекциями, и с единичными сущностями.
Но невозможно работать ТОЛЬКО с коллекциями. Как, например, тогда менять только одно свойство одной сущности (одно поле одной записи страницы)?

Цитата Сообщение от zelenprog Посмотреть сообщение
В этом примере вы описываете сценарий работы пользователя с одной сущностью.
VM+View умеет работать только с одной сущностью?
Разве нету каких-либо "специальных" View и ViewModel, которые умеют работать с коллекциями сущностей?
Есть конечно.
Но в основе всегда будет работа с одной сущностью.
Вот вам нужно поставить пользовательский флаг проверено. Его же нужно передать в репозиторий, сохранить. Не будете же вы работать исключительно только с коллекциями.

Цитата Сообщение от zelenprog Посмотреть сообщение
Модель ведь может работать только с объектами бизнес-логики, то есть с сущностями и их коллекциями. Как сюда "втиснуть" ValueTable?
А что в вашем случае Бизнес-Сущность?
Судя по вашему описанию их у вас просто нет.
Вся Бизнес-Логика построена вокруг работы с БД.

Цитата Сообщение от zelenprog Посмотреть сообщение
Наверно вы имели ввиду "Репозиторий конвертирует их в Строки DataTable"?
Нет.
Например, сейчас принято передавать в Модель+Репозиторий сущность:
C#
1
2
3
4
5
// В View
DataContext = new Person {Id=123, Name="Миша"};
 
// В VM
model.Update(person);
И эта сущность потом путешествует по всем слоям.

В реализации с DataTable придётся делать метод с кучей параметров:
C#
1
model.Update(id, name, lastName, birthday, ...);
Параметры метода будут в Репозитории, записаны в БД и в Таблицу которая в кеше. По факту, произойдёт их конвертация в одну строку таблицы.

Добавлено через 13 минут
Цитата Сообщение от zelenprog Посмотреть сообщение
При необходимости работать с объектом, его всегда можно получить из строки DataTable.
Для "обычной" работы Модели Репозиторий по прежнему может возвращать или Сущность или Коллекцию сущностей. Ясно, что какие-то бизнес-правила могут быть реализованы только для объекта.
"Классическая" Модель не должна работать с записями DataTable. Она должна получить объект из строки DataTable (пока не понятно как), и затем работать с объектом.
Можно. Но зачем?
Если нет никакой Бизнес Логики кроме работы с БД, то по факту вся "работа" (локальной) Модели - это "дирижирование" Репозиториями. Маппинг таблиц в коллекции (если это нужно) следует делать в Репозитории.
Но вполне можно работать и напрямую с Таблицами (кешом) на любом уровне.

Цитата Сообщение от zelenprog Посмотреть сообщение
Также у меня крутится мысль: а может быть сделать отдельный Репозиторий для работы с DataTable?
Лишнее переусложнение.
Для Модели разве это важно где, что хранится?
Для неё важна только Бизнес Логика, которой в вашем задании не просматривается.

Цитата Сообщение от zelenprog Посмотреть сообщение
Модель ведь может работать с любым количеством Репозиториев?
Репозиторий - это слой, когда мы говорим об архитектуре приложения в целом. Он может быть реализован из отдельных (независимых или зависимых) Репозиториев, для работы с разными данным.
Одна из типичных реализаций, когда для каждой таблице (более верно для каждого типа Бизнес Сущностей) создаётся свой отдельный Репозиторий, хотя при этом они все отражают одну и туже БД.

Цитата Сообщение от zelenprog Посмотреть сообщение
Во многих средах разработки есть что-то типа DataGridView + DataTable, а также binding. Это очень удобно, производительно.
Но это не вписывается в "классический" ООП, DDD, MVVM. Как это совместить?
MVVM - на это "по фиг". Там задаются требования к слоям и их связям.
ООП и DDD - согласен. DataTable плохо согласуются с принципами. Поэтому в современном Шарпе их используют крайне редко.
"Удобно" - как раз таки категорически нет. Именно поэтому и ушли от DataTable.

Добавлено через 1 минуту
"производительно" - ??? Что вы имеете ввиду под этим? И как определили? В сравнении с логикой и доступом БД, любой способ работы с ней и её отображения будет производительным.

Добавлено через 1 минуту
А если требуется суперзаточка под БД с многомиллионными пользователями, так там лучше напрямую использовать SQL.
0
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54
28.09.2023, 14:39  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Но невозможно работать ТОЛЬКО с коллекциями. Как, например, тогда менять только одно свойство одной сущности (одно поле одной записи страницы)?
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вот вам нужно поставить пользовательский флаг проверено. Его же нужно передать в репозиторий, сохранить. Не будете же вы работать исключительно только с коллекциями.
В этом случае из коллекции извлекается Сущность, у нее включаем флаг, передаем в Репозиторий.
Конечно, программа должна работать и с Сущностями, и с их коллекциями. Где-то удобно работать с таблицей (например, отображение в табличном виде на форме) - там можно использовать ValueTable. А где-то надо работать с конкретной сущностью.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
А что в вашем случае Бизнес-Сущность?
Судя по вашему описанию их у вас просто нет.
Есть Сущности. Как минимум: "СтарыйТовар", "НовыйТовар".
А еще есть мысль ввести Сущность "СоответствиеТоваров", а также Сущность "ФлагиСоответствия".

Цитата Сообщение от Элд Хасп Посмотреть сообщение
В реализации с DataTable придётся делать метод с кучей параметров:
model.Update(id, name, lastName, birthday, ...);
Параметры метода будут в Репозитории, записаны в БД и в Таблицу которая в кеше. По факту, произойдёт их конвертация в одну строку таблицы.
Я думал, что тут надо сделать по другому. Допустим пользователь нажимает "Записать" на текущей строке дерева соответствий, которое он просматривает.
Код будет примерно таким:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-----------
View - ViewModel:
-----------
lID = Form1.ActiveTable.ActiveRecord.ID;
model.Save(lID);
 
-----------
Model:
-----------
void Save (pID)
{
    // по указанному ID получаем Сущность "Узел соответствия".
    TUzel lUzel = mRepository_Sootvetstviya.GetUzelByOldTovarID(pID);
 
    // из этого узла берем ID нового и старого товаров и по этим ID-шникам 
    // получаем из кеша сущности "СтарыйТовар" и ...
    TOldTovar lOldTovar = mRepository_ValueTable_OldTovary.GetTovar(lUzel.OldTovarID);
 
    // ... "Новый товар"
    TNewTovar lNewTovar = mRepository_ValueTable_Tovary.GetTovar(lUzel.NewTovarID); 
 
    // Конвертируем данные из полей старого товара в данные нового товара
    ConvertData(lOldTovar, lNewTovar);
 
    // Записываем новый товар в базу данных
    mRepository_DB_Tovary.Save(lNewTovar);
}
Цитата Сообщение от Элд Хасп Посмотреть сообщение
>> Также у меня крутится мысль: а может быть сделать отдельный Репозиторий для работы с DataTable?
Лишнее переусложнение.
Для Модели разве это важно где, что хранится?
Для неё важна только Бизнес Логика, которой в вашем задании не просматривается.
В данном случае, как видно в коде выше, для бизнес-логики важно с каким источником-репозиторием она работает.
Мне кажется, для бизнес-логики "СтарыйТоварИзФайлаПереноса" и "СтарыйТоварИзValueTable" - это разные сущности.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
28.09.2023, 18:59
Цитата Сообщение от zelenprog Посмотреть сообщение
Есть Сущности. Как минимум: "СтарыйТовар", "НовыйТовар".
Это сущности для парсинга SQL запросов. Чаще всего такие сущности отражают записи той или иной таблицы БД.
Бизнес логики у вас нет, кроме работы с БД.

Цитата Сообщение от zelenprog Посмотреть сообщение
Конечно, программа должна работать и с Сущностями, и с их коллекциями. Где-то удобно работать с таблицей (например, отображение в табличном виде на форме) - там можно использовать ValueTable.
Так вот об этом же и весь "сыр-бор". Если нам нужны сущности для работы ВНЕ Репозитория. То парсинг SQL запросов в эти сущности - задача репозитория. Будет он это делать используя "ручные" Sql запросы, DataTable (ValueTable), какие-то реадеры или высокоуровневый EF - это внутреннее дело Репозитория. Никого кроме него это волновать не должно.
Если же разработчкик решает, что на уровнях выше нужны таблицы, а не сущности и их коллекции, то создавать сущности только "для правильного ОПП"... большого смысла в этом я не вижу.

Цитата Сообщение от zelenprog Посмотреть сообщение
В данном случае, как видно в коде выше, для бизнес-логики важно с каким источником-репозиторием она работает.
Мне кажется, для бизнес-логики "СтарыйТоварИзФайлаПереноса" и "СтарыйТоварИзValueTable" - это разные сущности.
Нет не важно.
Вы искусственно вывели это из функций репозитория и никак не можете "отлипнуть" от этой мысли.

Пример. У вас есть супербыстрый SSD, который работает быстрее ОЗУ. На нём все таблицы. Смысла создавать кеши нет.
То есть промежуточные ValueTable будут не нужны.
Понятно, что в этом случае может поменяться реализация Репозитория, так как она зависит от типа Хранилища.
Но изменение Хранилища не должно вызывать изменения Модели. В этом весь смысл выделения репозитория из Модели.
А вашей реализации придётся менять Модель. И значит вы неверно выделили функционал репозитория из Модели.

Добавлено через 14 минут
Цитата Сообщение от zelenprog Посмотреть сообщение
Код будет примерно таким:
Более менее.
Но несколько моментов.
Если мы "правильно работаем в ООП", то мы работаем с объектами. То есть выше модели у нас не int pID, а сам Узел соответствия. В котором не ид старого товара, а сам старый товар.

Так же мне не нравится вынос конвертации ConvertData(lOldTovar, lNewTovar);. На мой взгляд это функция Репозитория.
0
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54
04.10.2023, 12:37  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Бизнес логики у вас нет ...
В общем, получается, что проблема с выделением бизнес-логики.
Конечно же, бизнес-логика в этой программе есть, и достаточно сложная: старые товары (из разных источников), новые товары, соответствие между товарами по сложным "логическим" правилам, "жесткое" соответствие между товарами по ID-шникам, флажки для "отложенной" записи, признак выполнения записи.

Просто эта бизнес-логика явно не сформулирована.

Я сразу в начале темы поднял вопрос про работу с БД и с таблицами.
Поэтому, бизнес-логика осталась "в тени". А оказалось, что многое "завязано" на бизнес-логику.

Тут надо подумать.

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

Добавлено через 44 минуты
Цитата Сообщение от zelenprog Посмотреть сообщение
Конечно же, бизнес-логика в этой программе есть, и достаточно сложная: старые товары (из разных источников), новые товары, соответствие между товарами по сложным "логическим" правилам, "жесткое" соответствие между товарами по ID-шникам, флажки для "отложенной" записи, признак выполнения записи.
Дополню это примером нашей бизнес-логики.

Для конвертации старого товара в новый необходимо, чтобы пользователь указал дополнительные сведения.
Эти сведения пользователь указывает в Форме в нескольких полях.
При конвертации, значения этих полей должны использоваться как значения реквизитов нового товара в зависимости от значений реквизитов старого товара.

Например, при создании нового товара у него нужно сформировать значение реквизита "Организация", который обозначает предприятие, где был произведен этот товар. В старых базах такого реквизита нету. У старого товара "производителя" можно определить по ID-шнику. На форме (или в настройках программы) указывается "маска" ID-шников и соответствующее этой маске имя "производителя". Программа должна при конвертации посмотреть ID-шник старого товара, найти соответствующего "производителя", и записать его для нового товара в поле "Организация".
Получается, тут сведения из самого внешнего слоя UI должны "дойти" до самого нижнего слоя Репозитория через бизнес-логику.

Это только один "момент" правил нашей конвертации.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
04.10.2023, 14:47
Цитата Сообщение от zelenprog Посмотреть сообщение
что проблема с выделением бизнес-логики.
Здесь я имею ввиду несколько иное.
О БЛ, кроме, работы с Хранилищем.

Например, игровое приложение. В нём есть логика по сохранению состояния игры, игроков, всех юнитов. А есть ещё логика самой игры - то есть как юниты взаимодействуют друг с другом, как на игру влияют действия игрока.

Когда мы говорим об Архитектуре Приложения в ЦЕЛОМ мы выделяем слои Model, View и сопрягающий слой.
В этом случае под Бизнес Логикой понимается вся логика и сохранения, и самой игры.

Когда мы говорим об более детальной реализации Модели, о том что надо вынести из неё логику работы с Хранилищем, чтобы Игра могла работать и локально, и в сетке, и на Web сервере - тогда мы под БЛ подразумеваем более узкую функциональность, только ту часть логики которая не относится к работе с Хранилищем.

Поэтому в вашем случае, Бизнес Логика у вас есть, но она имеет отношение только к работе с Хранилищем. Какой-то иной логики в вашем ТЗ не просматривается. Следовательно и выделение Репозитория из Модели большого смысла не имеет, поскольку ваш Репозиторий по сути это и есть вся ваша Модель.

Добавлено через 48 минут
Цитата Сообщение от zelenprog Посмотреть сообщение
бизнес-логика в этой программе есть, и достаточно сложная: старые товары (из разных источников), новые товары, соответствие между товарами по сложным "логическим" правилам, "жесткое" соответствие между товарами по ID-шникам, флажки для "отложенной" записи, признак выполнения записи.
Но эта логика имеет отношение только к Работе с Хранилищем.

Добавлено через 2 минуты
Цитата Сообщение от zelenprog Посмотреть сообщение
Дополню это примером нашей бизнес-логики.
Это всё равно имеет отношение только к Хранилищу. Получили данные, вывели пользователю, он отредактировал, сохранили.
Всё. Больше никакой Логики нет.
0
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54
04.10.2023, 17:05  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Получили данные, вывели пользователю, он отредактировал, сохранили.
Всё. Больше никакой Логики нет.
Нет, пользователь ничего не редактирует.
Он только отмечает флажки "Проверен""Записывать", может указать соответствие между старым и новым товарами. А также пользователь заполняет общие поля, не привязанные ни к какому товару.
Эти сведения используются программой при автоматической конвертации.

Приведу еще пример бизнес-логики.
При загрузке данных из файла-переноса программа пытается установить "логическое" соответствие. Например, программа при загрузке формирует "временные" наименования товаров, которые формируются как преобразования оригинальных наименований (удаление лишних символов и преобразование в верхний регистр). Затем программа по этим "вычисленным" наименованиям сравнивает все старые товары со всеми новыми товарами.
Допустим, обнаружено соответствие.
Тогда программа для такого соответствия формирует "узел". Формат такого узла я описывал выше: первая строка узла - это наименование товара и флажки "Проверен"-"Записывать", вторая строка узла - это данные о старом товаре, третья строка узла - это данные о товаре из текущей БД. Таблица узлов отображается пользователю.
Пользователь смотрит на эти узлы, и если считает нужным, отмечает флажок "Записывать". Программа при включении флажка "Записывать", должна в специальную таблицу в БД (таблица соответствий) записать новую запись с ID старого товара и ID нового товара.
Это нужно для того, чтобы при следующем сеансе работы программа для этих товаров определила, что между ними уже установлено "жесткое" соответствие и не выполняла поиск "логического" соответствия по наименованиям (так как наименования могут поменяться).

Вот какие из описанных действий надо поместить в Репозитории? Какие - в слой Бизнес-логики? Какие - в Модель?
Какие Сущности тут надо выделить? Надо ли например выделить отдельную Сущность "ЖесткоеСоответствие"?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
04.10.2023, 17:36
Цитата Сообщение от zelenprog Посмотреть сообщение
Нет, пользователь ничего не редактирует.
Он только отмечает флажки "Проверен""Записывать", может указать соответствие между старым и новым товарами. А также пользователь заполняет общие поля, не привязанные ни к какому товару.
Эти сведения используются программой при автоматической конвертации.
А это не редактирование?
Редактирование же это не только ввод текста.

Цитата Сообщение от zelenprog Посмотреть сообщение
Вот какие из описанных действий надо поместить в Репозитории? Какие - в слой Бизнес-логики? Какие - в Модель?
Здесь нет логики кроме работы с Хранилищем.
Это всё относится к логике Репозитория.
Мы же с вами разбирались с этим.

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

Вопрос как это реализовать - это уже больше к вашим знаниям и опыту.
Не можете сделать Миграцию средствами БД или Сервера - делайте на локальном клиенте внешней логикой. Но выше уровня Репозитория здесь нет задачи.
Не надо "впихивать" не нужные сущности. Дополнительного слоя с выделенной логикой здесь не нужно.

Возможно вас вводит в заблуждение типичные массовые примеры по реализации Репозитория, в которых кроме запроса по одной таблице БД ничего нет.
Да, это наиболее типичная для Репозитория задача.
Но в общем случае задача Репозитория шире. Он не просто возвращает результат запроса, он работает с Бизнес Сущностями, создаёт их, конвертирует в нужные типы, сохраняет и т.д.

Запрос к старой БД -> Получение старого товара -> Отправка его в Репозиторий "Узлов". И там именно репозиторий создаёт из бизнес сущности "Старый товар" новый узел или добавляет его в имеющийся.
0
0 / 0 / 0
Регистрация: 22.09.2023
Сообщений: 54
06.10.2023, 12:53  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Запрос к старой БД -> Получение старого товара -> Отправка его в Репозиторий "Узлов". И там именно репозиторий создаёт из бизнес сущности "Старый товар" новый узел или добавляет его в имеющийся.
Какие объекты\классы выполняют эти действия? Репозиторий "Старых товаров"?
Получается, один Репозиторий может "управлять" другим Репозиторием?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16154 / 11275 / 2890
Регистрация: 21.04.2018
Сообщений: 33,153
Записей в блоге: 2
06.10.2023, 22:03
zelenprog, есть Репозиторий СЛОЙ и есть Репозиторий для управления каким-то конкретным Хранилищем для Конкретного типа.
Например, в EF DbContext это аккумуляция DbSet'ов. И каждый из них это Репозиторий определенного типа.

В вашем случае Репозиторий СЛОЙ тоже состоит из репозиториев по работе с отдельным типами. Ведь по сути общей логики не важно, например, где хранится УЗЕЛ. В таблице загруженной в памяти, в локальном Кеше выделенной БД, в общей БД с остальными данными и др. То есть у нас есть абстракции для Хранилищ нескольких типов: старый товар, узел, новый товар. И есть абстракция по "дерижированию" этими отдельным репозиториями. Внешние потребители работаю с этим "Дирижёром". То есть с точки зрения архитектуры приложения внешний интерфейс Дирижёра, это и есть интерфейс Модели.

Но следущий шаг. Есть ли смысл в реализации этого Дирижёра (Модели) отдельно от ViewModel?
В чем функция VM? Отразить Модель в своих свойствах.
Но если мы не преследуем цели делать мультисборное приложение, то зачем нам в Модели делать абстрактные методы и события, а не сделать Свойства, Команды и события "понимаемые" WPF?
Никакого смысла в этом нет. Это будет только реализация ради соблюдения неких идеалов.

Поэтому конкретно в вашем задании реализовать можно (и нужно) сразу как VM. В этом случае, что условно мы будем считать Моделью? Остаются только Репозитории типов. Поэтому мы получаем структуру View - View Model - Репозитории.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
06.10.2023, 22:03

Разделение DataSet на разные слои в сервис-ориентированном приложении. Как правильно?
Всем привет. Хочу создать простое приложение с сервис-ориентированной архитектурой, то есть классика: PresentationLayer --> ...

Ошибка "в указанном dsn архитектура драйвера и архитектура приложения"
Вот такая ошибка при нажатии на кнопку "Проверить соединение" Я прочитал, что это возможно из за того, что моя система 64, а...

Социальная сеть (сложная архитектура): аудио+видео+чаты+обмен данными +приложения (месенджеры и приложения)
Социальная сеть(сложная архитектура): аудио+видео+чаты+видео звонки с конференсом+обмен данными +приложения(месенджеры и внутренние...

Слои приложения, использование одного из другого
Здравствуйте. В литературе принципы хорошо описаны: делайте слабую связь между слоями благодаря интерфейсам, вот конкретики нет. ...

Архитектура приложения
Всем привет. Разрабатываю простой видеосервер. Задачи: принять аудио\видео поток от 4G камеры в формате RTP по UDP, записывать поток в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
После бана на Пикабу не работает авторизация аккаунта с Яндекса.
Hrethgir 09.07.2026
В частности https:/ / auto. ru/ logbook/ zapret-na-vozhdenie-posle-65-let_1cf28789-07b4-4c75-a2f7-4cd4edf9deeb тут хотел оставить комментарий такой Зрите в корень - монополизация на разработку программ. . .
GitDOS: Когда я решил скрестить MS-DOS, GitHub и Claude
MaGz GoLd 08.07.2026
Привет, Киберфорум! Хочу поделиться своим проектом, который, надеюсь, вас заинтересует. GitDOS — это веб-приложение, которое позволяет запускать DOS в браузере с тремя крутыми фичами: диски живут в. . .
Учебный мини "цифровой двойник" = (Сервер = Java + Flask_питон )+(3D = Гугловскаая 4T nvideo + google colab) +( WMS = Odoo на Docker)
anaschu 07.07.2026
Увидел в требованиях к вакансии создателя имитационных моделей связку (REst + Api + WMS + Anylogic + питон + 3D Nvideo), и решил посмотреть, что это такое. Из этого всего я работал более менее. . .
Море в объективе
kumehtar 06.07.2026
Хотел написать много проникновенных слов, но передумал. Оно само - говорит. Кто слышит тот слышит.
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru