Форум программистов, компьютерный форум, киберфорум
C#: ASP.NET MVC
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
1

EF и коллекции

15.03.2017, 17:04. Показов 2054. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Есть класс модели, где одно поле представляет собой коллекцию enum. В БД есть соответствующие таблицы, но там это сделано путем создания дополнительной таблицы. То есть допустим есть класс Item, есть enum Property. У класса Item есть поле List<Property>. В БД есть таблицы items, propeties и set_propety, в которой полю item_id соответствует property_id (ну и может быть несколько строк с одним и тем же item_id, если в коллекции несколько элементов)

Мне в данный момент редактировать БД не надо, просто прочитать бы, чтобы вывести список Property в представление для нужного Item. Подскажите примерно в каком направлении копать. Поможет ли LINQ, надо ли (и возможно ли это в EF) использовать sql-запрос? Или вообще ничего не получится?
Пока единственное, что приходит в голову - создать классы моделей, соответствующие таблицам, но класс SetProperty как-то некрасиво в C# будет выглядеть.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.03.2017, 17:04
Ответы с готовыми решениями:

Получение новой коллекции путем фильтрации элементов коллекции находящихся в другой коллекции
Всем привет, нуждаюсь в помощи знатоков) Имеется вот такая иерархия если представить в JSON: {...

Удаление элемента коллекции в коллекции коллекции )
Есть коллекция (к1), в ней элементы + коллекция (к2), Так вот в к2 тоже есть элементы, и из к2 надо...

Сделать сортировку коллекции вместо создания новой коллекции с передачей IOrderedEnumerable<T>
Есть: SortableObservableCollection&lt;T&gt; using System; using System.Collections.Generic; using...

Как удалить элемент из коллекции, во время перебора этой коллекции foreach?
Прив. Смотрите что. Есть сервер, на нем 2 класса - Server &amp; ClientConnection. При подключении...

23
3462 / 2473 / 695
Регистрация: 02.08.2011
Сообщений: 6,705
15.03.2017, 17:53 2
Цитата Сообщение от Alexey437 Посмотреть сообщение
set_propety
Посмотрел бы я в глаза тому, кто так называл таблицу.
Если бы это был Code First, то доступ к коллекциям был бы тривиален - через NavigationProperty на вашу коллекцию. Если один enum может включать в себя множество значений, то я бы вообще перепроектировал бд, сделав этот enum обычным свойством и повесив на него атрибут Flags.
Создайте класс c любым адекватным именем, и через TableAttribute, либо через Fluent API отображайте на нужную таблицу.

Добавлено через 8 минут
ps: И с существующей таблицей доступ к связанной коллекции реализуется через NavigationProperty.
1
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
15.03.2017, 18:30  [ТС] 3
IamRain, таблицу так никто не называл, это я тут написал, что в голову пришло. Класса Item тоже нет, он назван по предмету, который описывает, но на вопрос это не влияет, поэтому пишу Item, чтобы не грузить лишней инфой.

Про NavigationProperty сейчас почитаю, спасибо!

А про перепроектирование БД и про обычное свойство и Flags можно подробнее? Речь же о поле БД? Какого типа оно будет? (я с postgres работаю, если это имеет значение)
0
Usaga
15.03.2017, 18:44
  #4

Не по теме:

Цитата Сообщение от IamRain Посмотреть сообщение
Посмотрел бы я в глаза тому, кто так называл таблицу.
В случае использования PostrgeSQL это - нормальная практика. Там либо каждый раз в кавычки заключать идентификаторы (что в падлу), либо подчёркиваниями разделять слова.

0
3462 / 2473 / 695
Регистрация: 02.08.2011
Сообщений: 6,705
15.03.2017, 18:51 5
Цитата Сообщение от Alexey437 Посмотреть сообщение
Речь же о поле БД? Какого типа оно будет?
Да, полагаю, это будет целый тип, (int для postgres), хотя с Postgres почти не работал, могу ошибаться.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
15.03.2017, 18:55 6
Цитата Сообщение от Alexey437 Посмотреть сообщение
А про перепроектирование БД и про обычное свойство и Flags можно подробнее?
Речь о том, что "по правилам" лучше поддерживать нормализацию данных в БД и на каждый enum иметь в БД таблицу с соответствующими значениями. Тогда целостность данных будет сохранена.

Но многие на это забивают, ибо ENUM - штука (как правило) не редактируемая, и на каждое перечисление заводить по таблице, мягко говоря, лень и избыточно. Поэтому часто просто заводят поле типа INTEGER или аналогичное, где и хранят целочисленное (реже - строковое) представление значения из ENUM. Об этом и речь.
0
IamRain
15.03.2017, 18:56
  #7

Не по теме:


Usaga, я про значение, set_property - это же глагол. Таблица - коллекция строк. То есть должна иметь имя в виде существительного во множественном числе. Во всяком случае для меня привычно именно так.

0
Usaga
15.03.2017, 19:02
  #8

Не по теме:

IamRain, ну да, я понял. Но может быть тут мелось в виду "Свойство Множества" - Set Property)))) :D

0
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
15.03.2017, 21:00  [ТС] 9
Usaga, если свойство класса - просто enum, то я конечно его и храню в БД в виде int. Но тут вопрос про свойство класса List<enum> (то есть один ко многим). Это что же, в целом числе отдельные биты уставнавливать? В принципе можно, но наверно не самое красивое решение. Сначала попробую с NavigationProperty что-то придумать.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
16.03.2017, 04:52 10
Alexey437, в postrgesql есть тип данных "массив", который со свистом и улюлюканьем подходит под твою задачу.
1
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
20.03.2017, 15:57  [ТС] 11
Не, тип данных массив нарушает принципы реляционной БД. Я пару дней помучался и все-таки наладил, теперь все извлекается. Убрал таблицу propeties, которая описывала enum. Теперь один item просто связывается с несколькими числами с помощью второй таблицы.

На главной странице я просто в виде строки вывожу список значений. Но теперь вопрос как устроить вьюхи create и edit. Там надо чекбоксами делать, чтобы сразу был доступен мультивыбор. Насколько я понимаю, каждому чекбоксу должно соответствовать поле модели типа bool. Если делать просто что-то типа ContainsA (то есть коллекция содержит MyEnum.A), ContainsB и т.д. для каждого значения MyEnum, то это не слишком топорно будет? И будет ли работать в плане вставки в БД? Или может EF какие-то более хитрые и красивые способы знает?
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
20.03.2017, 16:09 12
Alexey437, чекбоксы нужно отправлять на сервер в виде массива одно типа данных. В твоём случае, скорее всего чисел.

Добавлено через 8 минут
Делается это примерно так. Только тип тега нужно другой - checkbox, но вы додумаетесь как надо.
2
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
20.03.2017, 18:39  [ТС] 13
Usaga, спасибо, интересная ссылка, пригодится на будущее. Но не придумал как ее к данному случаю применить. У меня ведь чекбоксы олицетворяют коллекцию, которая является только одним из полей класса Item. И в качестве параметра метода POST я получаю целиком объект Item. Как же туда еще какой-то массив передать?

Пока сделал таки ContainsA, ContainsB, ... и оно даже работает! Только не очень красиво выглядят эти Contains в классе - почти одинаковый код повторяется 6 раз (у меня в enum 6 значений)
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
21.03.2017, 02:56 14
Лучший ответ Сообщение было отмечено Alexey437 как решение

Решение

Alexey437, звучик как какая-то ерунда. Перечисление всегда должно быть представлено одним полем, либо в виде единственного значения, либо в виде набора флагов. У тебя же ни то, ни другое.

Если у тебя должно быть только шесть значений\признаков, которые могут быть одновременно, то это уже однозначно флаги, которые могут поместиться в один байт. Значит и хранить это дело можно в БД в таблице самой сущности в виде однобайтового поля (uint8 или аналогичного), без отдельных таблиц. Париться о нормализации и реляционности данных в таком случае смысла не имеет.

Представить данные признаки в представлении можно именно массивом булевых значений. Суть в том, что тебе понадобится две модели: одна - модель уровня данных (то, что из БД вытаскивается), вторая - модель представления (то, что будет использоваться для вывода\ввода пользователю). Т.е. нужно на каждом логическом уровне представлять одни и теже данные наиболее удобным для этого уровня образом.

Т.е. это должно выглядеть так: ты вытаскиваешь и БД оригинальную запись с флагами, создаёшь объект модели для представления, копируешь из оригинального объекта данные, попутно конвертируя нужные поля (в данном случае: байт флагов в массив из шести элементов) и уже адаптированные данные отображаешь пользователю в представлении.

Соответственно, обратный процесс аналогичен. Так и только так и добъёшься и удобного хранения данных в БД и удобного же их отображения в представлении (в случае, когда одна модель неудобна для всех её применений, как у тебя).
0
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
21.03.2017, 10:16  [ТС] 15
Ну я немного выше упоминал возможность варианта с отдельными битами, тогда никто не сказал, что это единственно правильное решение. Теперь я уже сделал по-другому и все с нуля переделывать не буду.
Вообще тут жаль, что в C# нет возможности передавать параметр в свойство, тогда не нужно было бы писать отдельное свойство для каждого значения enum и все было бы идеально.
Ну либо помогла бы возможность в строго типизированном представлении привязывать не к свойству, а к методу класса. Что тоже невозможно, насколько я понимаю.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
21.03.2017, 10:59 16
Alexey437, ну, до твоего последнего сообщения не было до конца ясно, что именно и как ты хочешь сделать. Вот и сомневались.

Цитата Сообщение от Alexey437 Посмотреть сообщение
Вообще тут жаль, что в C# нет возможности передавать параметр в свойство, тогда не нужно было бы писать отдельное свойство для каждого значения enum и все было бы идеально.
Вот это непонятно, что имелось в виду. Перечисление можно использовать как набор флагов в одном поле\свойстве. Зачем могло понадобиться заводить по полю на значение?..
0
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
21.03.2017, 11:22  [ТС] 17
У меня строго типизированное представление. Чекбоксы я создаю так
@Html.CheckBoxFor(model => model.PropertyA, false)
@Html.CheckBoxFor(model => model.PropertyB, false)
@Html.CheckBoxFor(model => model.PropertyC, false)

Оно работает, но для красоты хочется чтобы было типа такого
@Html.CheckBoxFor(model => model.Property(MyEnum.A), false)
@Html.CheckBoxFor(model => model.Property(MyEnum.B), false)
@Html.CheckBoxFor(model => model.Property(MyEnum.C), false)

чтобы в классе Property не дублировать. Как именно в представление можно передать одно свойство вместо шести? Надо ведь как-то параметр передать, иначе как чекбокс поймет за какое значение он отвечает?

Добавлено через 9 минут
Сейчас попробовал индексатор приделать к коллекции. Что-то типа
C#
1
2
3
4
5
6
7
8
public bool this[int index]
{
    get { ContainProperty((MyEnum)index); }
    set {
         if (value) AddProperty((MyEnum)index);
         else RemoveProperty((MyEnum)index);
    }
}
В представлении написал
@Html.CheckBoxFor(model => model[(int)MyEnum.A], false)
но такой вариант почему-то не работает. Компилируется и запускается, но в индексатор даже не заходит.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
21.03.2017, 12:16 18
Alexey437, ты, видимо, меня не понял, когда я говорил про разные модели и преставление свойства в виде массива. Грубо говоря, это можно было бы сделать так:

Кликните здесь для просмотра всего текста

C#
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using System;
using System.Collections.Generic;
 
namespace ConsoleAppExperiments
{
    [Flags]
    enum Property
    {
        A = 1,
        B = 2,
        C = 4,
        D = 8,
        E = 16,
        F = 32
    }
 
    class PropertyDataModel
    {
        public Property Prop { get; set; }
    }
 
    class PropertyViewModel
    {
        public PropertyViewModel(PropertyDataModel dataModel)
        {
            Properties = new bool[6];
 
            for (int i = 0; i < 6; i++) {
                Properties[i] = ((int)dataModel.Prop & (1 << i)) != 0;
            }
        }
 
        public IList<bool> Properties { get; set; }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            var dm = new PropertyDataModel {
                Prop = Property.A | Property.D
            };
 
            var vm = new PropertyViewModel(dm);
 
            foreach (bool b in vm.Properties) {
                Console.WriteLine(b);
            }
 
            Console.WriteLine("\npress any key...");
            Console.ReadKey();
        }
    }
}


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

Добавлено через 3 минуты
И при создании чекбоксов с помощью хелпера, указывать им одно имя (если брать мой фрагмент кода - Properties), тогда значения чекбоксов прийдут в виде того же массива (я давал ссылку на эту тему) внутри модели.
1
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
21.03.2017, 12:42  [ТС] 19
Спасибо, попробую.

А почему на заработал мой индексатор, не знаешь? Просто интересно.
0
Эксперт .NET
12079 / 8388 / 1281
Регистрация: 21.01.2016
Сообщений: 31,601
21.03.2017, 12:52 20
Alexey437, я не знаю, что скрывается за методами, которые вызываеются в индексаторе. В любом случае, такой подход неудачен. Предложенный мной тоже, наверное, не самый лучший, но всё же.
0
21.03.2017, 12:52
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.03.2017, 12:52
Помогаю со студенческими работами здесь

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

Анонимные коллекции в другие коллекции, как?
Здравствуйте. Говорю сразу, я не уверен что есть такой термин как анонимная коллекция. Наверно...

Комбобокс и коллекции. Или коллекции комбобоксов
Ребят, изобразил пример, посмотрите пожалуйста ...там при двойном щелчке на, допустим &quot;Профессия...

Удаление коллекции объектов из коллекции
Доброго дня. Подскажите каким образом можно удалить коллекцию объектов из коллекции с помощью linq?...

Заменить элементы одной коллекции на элементы другой коллекции
Всем привет, у меня такой вопрос: есть 2 коллекции: List&lt;Person&gt; list1 = new List&lt;Person&gt;...

Коллекции
Народ, нуждаюсь в вашей помощи Есть ли стандартный класс или библиотек или кое-что другое чем...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru