Форум программистов, компьютерный форум, киберфорум
Наши страницы
C#: ASP.NET MVC
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/6: Рейтинг темы: голосов - 6, средняя оценка - 5.00
Alexey437
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
1

EF и коллекции

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

Есть класс модели, где одно поле представляет собой коллекцию 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)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.03.2017, 17:04
Ответы с готовыми решениями:

Заполнение коллекции
Добрый день, мне нужно передать в коллекцию данные, вводимые из представления пользователем,...

Коллекции и массивы - проблемы..
Здраствуйте, возникла такого рода проблема: Пишу на ASP(VBScript) классы и мне нужно организовать...

Обновление списка из коллекции
Не давно начал изучать ASP MVC. Проблема такая есть форма с двумя тексбоксами и кнопка. При нажатии...

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

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

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

Добавлено через 8 минут
ps: И с существующей таблицей доступ к связанной коллекции реализуется через NavigationProperty.
1
Alexey437
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
IamRain
1436 / 1275 / 403
Регистрация: 02.08.2011
Сообщений: 3,770
15.03.2017, 18:51 5
Цитата Сообщение от Alexey437 Посмотреть сообщение
Речь же о поле БД? Какого типа оно будет?
Да, полагаю, это будет целый тип, (int для postgres), хотя с Postgres почти не работал, могу ошибаться.
0
Usaga
Эксперт .NET
5792 / 4040 / 718
Регистрация: 21.01.2016
Сообщений: 15,802
Завершенные тесты: 2
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
Alexey437
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
15.03.2017, 21:00  [ТС] 9
Usaga, если свойство класса - просто enum, то я конечно его и храню в БД в виде int. Но тут вопрос про свойство класса List<enum> (то есть один ко многим). Это что же, в целом числе отдельные биты уставнавливать? В принципе можно, но наверно не самое красивое решение. Сначала попробую с NavigationProperty что-то придумать.
0
Usaga
Эксперт .NET
5792 / 4040 / 718
Регистрация: 21.01.2016
Сообщений: 15,802
Завершенные тесты: 2
16.03.2017, 04:52 10
Alexey437, в postrgesql есть тип данных "массив", который со свистом и улюлюканьем подходит под твою задачу.
1
Alexey437
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
Usaga
Эксперт .NET
5792 / 4040 / 718
Регистрация: 21.01.2016
Сообщений: 15,802
Завершенные тесты: 2
20.03.2017, 16:09 12
Alexey437, чекбоксы нужно отправлять на сервер в виде массива одно типа данных. В твоём случае, скорее всего чисел.

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

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

Решение

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

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

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

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

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

Цитата Сообщение от Alexey437 Посмотреть сообщение
Вообще тут жаль, что в C# нет возможности передавать параметр в свойство, тогда не нужно было бы писать отдельное свойство для каждого значения enum и все было бы идеально.
Вот это непонятно, что имелось в виду. Перечисление можно использовать как набор флагов в одном поле\свойстве. Зачем могло понадобиться заводить по полю на значение?..
0
Alexey437
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
Usaga
Эксперт .NET
5792 / 4040 / 718
Регистрация: 21.01.2016
Сообщений: 15,802
Завершенные тесты: 2
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
Alexey437
0 / 0 / 0
Регистрация: 26.06.2016
Сообщений: 35
21.03.2017, 12:42  [ТС] 19
Спасибо, попробую.

А почему на заработал мой индексатор, не знаешь? Просто интересно.
0
Usaga
Эксперт .NET
5792 / 4040 / 718
Регистрация: 21.01.2016
Сообщений: 15,802
Завершенные тесты: 2
21.03.2017, 12:52 20
Alexey437, я не знаю, что скрывается за методами, которые вызываеются в индексаторе. В любом случае, такой подход неудачен. Предложенный мной тоже, наверное, не самый лучший, но всё же.
0
21.03.2017, 12:52
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.03.2017, 12:52

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru