Форум программистов, компьютерный форум, киберфорум
C#: ASP.NET MVC
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.97/37: Рейтинг темы: голосов - 37, средняя оценка - 4.97
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281

Связанные данные в трехуровневой архитектуре

22.09.2019, 23:23. Показов 8722. Ответов 150
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Как подтягивать связанные данные в трехуровневой архитектуре?
У меня есть три уровня данных.
На уровне DAL там понятно как обращаться к связанные данным, там есть связи.
Вот на пример в DAL заказ у меня выглядит так
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  
public class Order
    {
        public Order()
        {
            this.OrderItems = new HashSet<OrderItem>();
        }
        public Guid OrderId { get; set; }
        public Guid CustomerId { get; set; }
        public DateTime OrderDate { get; set; }
        public DateTime? ShipmentDate { get; set; }
        public int? OrderNumber { get; set; }
        public Guid? StatusId { get; set; }
 
 
        public virtual Customer Customer { get; set; }
        public virtual ICollection<OrderItem> OrderItems { get; set; }
        public virtual Status Status { get; set; }
    }
Уровень BLL DTO
C#
1
2
3
4
5
6
7
8
9
 public class OrderDTO
    {
        public Guid OrderId { get; set; }
        public Guid CustomerId { get; set; }
        public DateTime OrderDate { get; set; }
        public DateTime? ShipmentDate { get; set; }
        public int? OrderNumber { get; set; }
        public Guid? StatusId { get; set; }
    }
Уровень представления у меня 2 модели
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Просто вывод списка заказов
    public class OrderListModel
    {
        public Guid OrderId { get; set; }
        public Guid CustomerId { get; set; }
        public int? OrderNumber { get; set; }
        public Guid? StatusId { get; set; }
    }
 
//Вывод более подробной информации 
 public class OrderViewModel
    {
        public Guid OrderId { get; set; }
        public Guid CustomerId { get; set; }
        public DateTime OrderDate { get; set; }
        public DateTime? ShipmentDate { get; set; }
        public int? OrderNumber { get; set; }
        public Guid? StatusId { get; set; }
        
    
        public IEnumerable<OrderItemListModel> ItemsList { get; set; }
    }
Из этого следует вопрос как получить связанные данные. Что бы на пример вместо ID статуса вылезала надпись (в таблице статус 2 поля (ID,Name)) мне нужно чтобы он подставлял Name. И что бы в подробностях заказа был список товаров.


Как вариант переносить связи на каждый уровень.
Какие еще варианты?
Миниатюры
Связанные данные в трехуровневой архитектуре  
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
22.09.2019, 23:23
Ответы с готовыми решениями:

Удалить связанные данные
Допустим есть две таблицы: &quot;Отцы&quot; и &quot;Дети&quot;. В таблице &quot;Отцы&quot; следующие столбцы: idFather, LastName, FirstName, Age. В таблицы...

Как создать приложение с трехуровневой архитектурой?
Здравствуйте. Я хотел попросить помощи у гуру программистов. Как создать приложение с трех уровневой архитектурой? В своей программе...

Поделитесь информацией о приложениях с трёхуровневой архитектурой
Если кто то может поделитесь информацией о приложениях с трёхуровневой архитектурой. Если даже кто-то делал подобные проекты поделитесь...

150
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
24.09.2019, 20:24  [ТС]
Студворк — интернет-сервис помощи студентам
sau, в данном случае нет разницы, пока нет, но так я смогу спокойно обогатить DTO если захочу.
Как в итого мне быть с данной ситуации, как удалять по id?

Добавлено через 6 минут
Вернее я ошибся, не по id, а по коду. И не удалять, а изменять
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
24.09.2019, 21:34  [ТС]
sau, В общем вот что происходит.
На View модели ID все, теряется, а чтобы EF обновил, нужен ID
Миниатюры
Связанные данные в трехуровневой архитектуре   Связанные данные в трехуровневой архитектуре   Связанные данные в трехуровневой архитектуре  

Связанные данные в трехуровневой архитектуре   Связанные данные в трехуровневой архитектуре  
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
24.09.2019, 21:37  [ТС]
И вот сама ошибка
Миниатюры
Связанные данные в трехуровневой архитектуре  
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
24.09.2019, 21:53
Cherry_Pie,
C#
1
2
3
4
5
6
7
public void EditItem(Item bllItem)
{
    var dataItem = dataItemRepository.Find(ItemQuerySpecification.ByCode(bllItem.Code));
    mapper.Map(bllItem).To(dataItem);
    dataItemRepository.Update(dataItem);
 
}
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
24.09.2019, 22:00  [ТС]
Цитата Сообщение от sau Посмотреть сообщение
ItemQuerySpecification
А это что за метод?
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
24.09.2019, 22:06
А это что за метод?
реализация паттерна спецификаций , которая возвращает expression выражение для репозитория.
вида Expression<Func<T, bool>> , которое может перевариваться тем или иным образом в зависимости от типа репозитория , например dbcontext-ом в SQL выражение.
в общем , если попроще описать это , то такое:
dbContext.Items.Find(item=>item.Code==bl lItem.Code)
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
24.09.2019, 23:13  [ТС]
Цитата Сообщение от sau Посмотреть сообщение
реализация паттерна спецификаций , которая возвращает expression выражение для репозитория.
вида Expression<Func<T, bool>>
А можно как-то попроще? я нашел только 1 статью по этому делу (Верно ищу ? https://enterprisecraftsmanshi... mentation/), но не понял как реализовать мой случай.
Я так понял, что я просто должен в сервисе найти item по коду в репозитории и просто приравнять ему поля пришедшие с View? Правильно?

Вот что я придумал(
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
public void EditItem(ItemDTO itemDTO)
        {
            var dataItem = _unitOfWork.ItemRepository.GetByCode(itemDTO.Code);
 
            Item _itemDB = new Item();
            _itemDB.ItemId = dataItem.ItemId;
            _itemDB.Code = itemDTO.Code;
            _itemDB.Name = itemDTO.Name;
            _itemDB.Price = itemDTO.Price;
            _itemDB.CategoryId = itemDTO.CategoryId;
 
            _unitOfWork.ItemRepository.Update(_itemDB);
        }
НО пишет, что этот элемент уже используется

Добавлено через 8 минут
И еще вопрос, при добавлении записей в таблице Code должен генерироваться, а не что бы пользователь вводил вручную. Для этого нужно в BL в DTO добавить метод для генерации этого кода?
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
24.09.2019, 23:56
Цитата Сообщение от Cherry_Pie Посмотреть сообщение
А можно как-то попроще?
такой репозиторий как у Вас не содержит логику построения запроса т.к критерий построения запроса может зависеть от условий бизнеслогики , что бы сделать его более универсальным и независимым от различных конфигураций запросов , делаем ему интерфейс в общей форме, тобишь репозиторий реализует метод T Find(Expression<Func<T, bool>> query)
где query мы можем строить каким угодно образом , хоть по коду , хоть по ID.
мы можем запросить так _unitOfWork.ItemRepository.Find(item=>it em.Code==itemDTO.Code);
или так _unitOfWork.ItemRepository.Find(item=>it em.ID==123); , интерфейс репозитория при этом никак не затрагивается . меняются лишь выражения запросов.

Спецификации нужны тогда , когда у Вас получается множество одинаковых сложных запросов - например Вы ищите обьект по нескольким свойствам и делаете это в нескольких методах - на удалении , на обновлении , уже как минимум в двух местах будет один и тот же запрос на поиск обьекта. , в случае если структуру запроса нужно будет изменить - ее придется менять как минимум в двух и более местах - во избежании чего мы изолируем логику построения expresion выражений в одном месте = спецификация.

Понятно , что реализации спецификаций могут быть самые разные , но в NET , применительно к репозиториям , реализация через expression минималистична и достаточна.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void EditItem(Item bllItem)
{
    //var dataItem = dataItemRepository.Find(item=>item.Code==bllItem.Code && item.Code!=null);  один разок 
    var dataItem = dataItemRepository.Find(ItemQuerySpecification.ByCode(bllItem.Code));
    mapper.Map(bllItem).To(dataItem);
    dataItemRepository.Update(dataItem);
    ....
    //прочая бизнеслогика...
}
 
public void RemoveItem(Item bllItem)
{
    //var dataItem = dataItemRepository.Find(item=>item.Code==bllItem.Code && item.Code!=null); и еще один разок
    var dataItem = dataItemRepository.Find(ItemQuerySpecification.ByCode(bllItem.Code));
    mapper.Map(bllItem).To(dataItem);
    dataItemRepository.Delete(dataItem);
    ....
    //прочая бизнеслогика...
 
}
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
25.09.2019, 00:08  [ТС]
sau, Так, получается во всех репозиториях я должен прописать метод find?а в нем что? Писать Linq запрос .where item.code=чему?

Добавлено через 5 минут
Вот если я захочу сделать поиск по категориям, по textbox, сортировку по цене, то я могу не писать новый метод в репозиториях, а просто добавить в спецификацию новые методы и будет что вроде: itemqueeyspecification. SortByPrice?
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
25.09.2019, 00:17
Cherry_Pie, если у Вас там dataContext , то DbSet уже принимает на входе Expression выражение ,
T Find(Expression<Func<T, bool>> query)
{
return dataContext.Set<T>().Find(query);
}

ну и да , тут речь идет о джинерик репозитории Repository<T>, более универсальная реализация.
в общем , я сейчас совсем запутаю ).

Добавлено через 1 минуту
Цитата Сообщение от Cherry_Pie Посмотреть сообщение
itemqueeyspecification. SortByPrice?
да , можно и так , а можно определить базовый интерфейс спецификации SortBy , а уже конкретная реализация будет по тому или иному полю строить условие запроса
притом SortByPrice ничего не сортирует , оно лишь строит выражение сортировки , которое потом в репозитории обрабатывается.
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
25.09.2019, 00:22  [ТС]
sau, О Господи, я не думал что такое задание выматает мне все нервы.
В общем в моем случае нужно просто сделать данный код и все?

C#
1
2
3
4
5
6
7
public void EditItem(ItemDTO itemDTO)
{
    var dataItem = dataItemRepository.Find(item=>item.Code== itemDTO.Code && item.Code!=null); 
    mapper.Map(bllItem).To(dataItem);
    dataItemRepository.Update(dataItem);
   
}
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
25.09.2019, 00:40
Цитата Сообщение от Cherry_Pie Посмотреть сообщение
О Господи, я не думал что такое задание выматает мне все нервы.
ну а как Вы хотели , люди годами бест.практик вырабатывают , потом книжки по 500 листов пишут , что бы концепцию разьяснить , и мне тут в двух словах на пальцах это сложно упаковать ).
нужно учебник читать и не один.

Я , кстати кидал пример на CMS магазина , там может и не шибко замороченная архитектура , но вполне себе юзабельная для целей магазина , как раз ваш случай.- и есть трехлаер. , есть репозитории , сервисы , модели.
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
25.09.2019, 00:42  [ТС]
sau, Да, я посмотрел, ничерта не понял)) не слишком замороченная архитектура? Для меня это был страшный сон
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
25.09.2019, 19:04  [ТС]
Цитата Сообщение от sau Посмотреть сообщение
//var dataItem = dataItemRepository.Find(item=>item.Code= =bllItem.Code && item.Code!=null); *один разок
Начал делать, но я не понял(
Как мне в репозитории метод Find реализовать?
у меня имеется GetByCode
C#
1
2
3
4
5
  public Item GetByCode(string code)
        {
            var query = context.Items.Where(s => s.Code == code).FirstOrDefault();
            return query;
        }
Добавлено через 2 минуты
Цитата Сообщение от Cherry_Pie Посмотреть сообщение
mapper.Map(bllItem).To(dataItem);
И как у вас маппер такой короткий?
У меня он длинный почему-то
C#
1
2
3
 
var mapper = new MapperConfiguration(cfg => cfg.CreateMap<ItemCreateModel, ItemDTO>()).CreateMapper();
ItemDTO _itemDTO = mapper.Map<ItemCreateModel, ItemDTO>(itemCM);
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
25.09.2019, 20:12
Лучший ответ Сообщение было отмечено Cherry_Pie как решение

Решение

Цитата Сообщение от Cherry_Pie Посмотреть сообщение
Как мне в репозитории метод Find реализовать?
C#
1
2
3
4
5
6
public virtual IQueryable<T> Table => context.Set<T>();
 
public T Find(Expression<Func<T, bool>> query)
{
       return Table.FirstOrDefault(query);
}
1
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
25.09.2019, 23:13  [ТС]
Цитата Сообщение от sau Посмотреть сообщение
public T Find(Expression<Func<T, bool>> query)
{
return context.Set<T>().FirstOrDefault(query);
}
ОГРОМНОЕ СПАСИБО!!!!!!!!!!!

Добавлено через 51 минуту
sau, А как можно создавать уникальный Code? генерировать его и потом проверять есть ли элемент с таким Code?
И где генерировать? В сервисе?

Добавлено через 1 час 57 минут
sau, Является ли правильной моя генерация кода?
Код должен выглядеть "ЧЧ-ЧЧЧЧ-ББ-ЧЧ" (ч-число, б- буква)
В сервисе
C#
1
2
3
4
5
6
7
8
9
10
11
public void AddItem(ItemDTO itemDTO)
        {
            itemDTO.ItemId = Guid.NewGuid();
//Тут вызываю генератор
            itemDTO.Code = GenerateCode();
            itemDTO.DataRegistration = DateTime.Now;
 
            var mapper = new MapperConfiguration(cfg => cfg.CreateMap<ItemDTO, Item>()).CreateMapper();
            Item _itemDB = mapper.Map<ItemDTO, Item>(itemDTO);
            _unitOfWork.ItemRepository.Insert(_itemDB);
        }
Так же в сервисе
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public string GenerateCode()
        {
            bool check = false;
            int value1=0;
            int value2 = 0;
            string value3 = "";
            int value4 = 0;
            string fullCode = "";
            while (!check)
            {
                Random rnd = new Random();
                value1 = rnd.Next(10, 99);
                value2 = rnd.Next(1000, 9999);
//Вызов генерации строки
                value3 = RandomString();
                value4= rnd.Next(10, 99);
                fullCode = (value1.ToString()+"-" + value2.ToString() + "-" + value3  + value4.ToString()).ToString();
//Метод проверки на существующий код
                check = CheckCode(fullCode);
            }
            return fullCode;
        }
Метод генерации строки
C#
1
2
3
4
5
6
7
8
9
10
11
public static string RandomString()
            Random rand = new Random();
            char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
            string word = "";
            for (int j = 0; j < 2; j++)
            {
                char lette =Convert.ToChar(letters[rand.Next(0, 25)]);
                word += lette;
            }
            return word;
        }
Проверка на существование кода.
C#
1
2
3
4
5
6
7
8
9
public bool CheckCode(string code)
        {
            bool isUnique = false;
            Item itemDB = _unitOfWork.ItemRepository.GetByCode(code);
            if (itemDB == null)
                isUnique = true;
            else isUnique = false;
            return isUnique;
        }
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
25.09.2019, 23:33
Cherry_Pie, смотря что за код , если код продукта то продукт маркируется по правилам производителя , у них своя БД и свой учет номеров. , по этому он поступает из внешней системы и в вашей БД хранится в оригинальном виде.
Если это код заказа в вашей системе , то сами придумываете ему алгоритм гарантирующий уникальность , можно сделать на основе автоинкремента записи в БД.
while (!check) - слишком длительная схема , код может почти никогда не сгенерироваться уникальным.
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
25.09.2019, 23:36  [ТС]
sau, да, про код производителя я знаю, по заданию сделать код товаров, заказчиков быть именно в «выдуманны форматах».
А вот код видимо нужно в автоинкрементируемых.
А как в code first не у ключа сделать автоинкрементных?
0
 Аватар для sau
2875 / 2080 / 386
Регистрация: 22.07.2011
Сообщений: 7,837
25.09.2019, 23:56
Цитата Сообщение от Cherry_Pie Посмотреть сообщение
А как в code first не у ключа сделать автоинкрементных?
у ключа , но на основе ключа потом можно и код сделать уже на уровне логики приложения , одно поле генерируется по значению другого поля.
но вообще , опора на автоинкримент не всегда хороший вариант , если Вы например решите перенести часть товаров в другую БД - в целях оптимизации , снижения нагрузки на сервер и т.п. , то там счетчики записей будут уже свои и не дадут гарантию уникальности кода по нескольким БД , так что в идеале нужен свой счетчик.

И кстати , если код товара уникален по самим характеристикам товара , тогда ни счетчики , ни какие либо прочие зависимости не нужны. - генерируется на основе характеристик.
0
16 / 10 / 4
Регистрация: 16.12.2017
Сообщений: 281
26.09.2019, 00:19  [ТС]
Цитата Сообщение от sau Посмотреть сообщение
И кстати , если код товара уникален по самим характеристикам товара , тогда ни счетчики , ни какие либо прочие зависимости не нужны. - генерируется на основе характеристик.
эмм что))? не понял, на основе каких характеристик генерируется товар?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
26.09.2019, 00:19

Не могу получить связанные данные из БД
Не могу получить связанные данные из базы PositionName, DepartmentName, OfficeName, EmployerName. Посоветуйте что можно сделать? Есть...

Не получается сделать связанные данные
Вот код программы using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using...

Добавить данные в связанные таблицы postgres
Здравствуйте. Столкнулся с проблемой, Есть таблица комплектующих с полями idgr, idedzim, name. Поля idgr и idediz связаны с полями таблиц...

Как вывести связанные данные из модели?
Есть модель public class Game { public int Id { get; set; } public string Name { get; set; } ...

Не правильно отображаются связанные данные из БД в DataGridview
в DataGridview загружаю данные и таблицы БД (скрин 3), в таблице одна колонка подстановка данных из другой таблицы. Колонка ФИО связана с...


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Когда логика программы не спасает от человеческих ошибок
Maks 18.08.2026
В последнее время всё чаще и чаще сталкиваюсь с таким явлением, как абсолютная невнимательность (или глупость) пользователей. Проявляется это чаще всего на работе в коллективе. Допустим, человек с. . .
Лето уходит
kumehtar 17.08.2026
Мысли в слух
kumehtar 17.08.2026
Забавно, насколько сейчас стала доступна информация. Например о магии, духовном развитии, медитациях, и других подобных направлениях, ранее зачастую тайных, передаваемых от учителя к ученику. Хотя. . .
Перемещение строк из ТЧ в другой документ с учетом текущего пробега
Maks 17.08.2026
Реализация из решения ниже выполнена на примере нетипового документа "Автозапчасти", с ТЧ "Шины". За основу взят алгоритм отсюда: https:/ / www. cyberforum. ru/ blogs/ 359708/ 10838. html Задача: . . .
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru