.NET Fest: полная программа конференции на сайте. Присоединяйся к самому большому .NET ивенту
×Закрыть

Что лучше использовать в качестве Data Access Layer для обеспечения возможности динамической конфигурации колонок таблиц?

Необходимо создать систему, в которой некоторые таблицы будут конфигурироваться пользователем после установки системы. Например, для таблицы, которая содержит список товаров, необходимо обеспечить возможность добавлять новые колонки различных типов. Требований к серверу БД пока нет. Это может быть SQL Server Express.
Вопросы:
1. Есть ли какой-то ORM или Framework который обеспечивает такую возможность «из коробки»?
2. Что лучше для этого использовать: ORM (Entity Framework, NHibernate и прочие), ADO.NET или что-то еще?

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
ну есть всякие динамискы, 1с и т.д. системы сос воим языком и средствами разработки.
а для обычного приложения даже не представляю как такая идея может прийти с динамическим добавлением столбцов в таблицу ( ведь при использвании ORM у вас фактически меняется entity, типа добавляется новая проперть классу).
В принципе можете поискать статьи на тему хранения иерархических сущностей в реляционный бд

или самый простой вариант — можно например сделать поле типа XML и там в сериализованном виде хранить ваш объект. Главное потом при десериализации правильно понять что за хрень там хранится :-)

Для варианта с добавлением колонок в таблицы, что будет лучше в качестве Data Access компонентов для CRUD-операций и выбора данных для отчетов?

Получается что использовать ORM смысла нет?

А вы попробуйте рассмотреть вариант с группировкой в гриде по конкретному товару — ИМХО, это более кузяво и реальнее. Вот например, нижеуказанный пример с extragrid онлайн:
demos.devexpress.com/...tionWindow.aspx
1) Зайдите по ссылке
2) Представим, что колонка «Country» — это товары (т.е., олицетворение колонки товара, из-за которой сыр-бор)
3) Берем, и перетаскиваем ее на панель группировки (туда, где написано «Drag a column header here to group by that column »)

4) Получаем в гриде раскрываемые агрегированные (по желанию) списки, в разрезе товаров.

При этом, отдельных колонок под каждый товар мы не добавляли — они разрулились по ссылке (типа ProductID в каждой строчке)

Естественно, начальную настройку лэйаута мы можем сделать в коде.

Вот, например, мы хотим получить отчет по продажам товаров. Первый вариант — это динамические колонки, с названиями товаров, как вы хотите. Да, неплохо, если не учитывать все нижесказанное о головняке. И если не учитывать, что при наличии 20 колонок и больше фиг оно поместится на формат А4, или будет офигенно широкий скролл на веб-странице, потому что разрастаться в ширину можетт бесконечно, т.к. кол-во товаров влияет на ширину отчета.
Вариант с группировкой — у вас физически будет 2 колонки: название товара (ну или ссылка — я абстрактно пишу), и объем продаж по нему. При группировке, все очень красиво распахнется по высоте отчета, потому что все идет в разрезе как в первом случае, но разрез — вертикальный. А если группировать транзакции по товару — так оно еще и сделает консолидацию в одну строчку.

Так что вариант с динамическими колонками — ИМХО, и с точки зрения юзабилити неюзабелен.

p.p.s. А группировать можно и группировку тоже. Допустим, на том онлайновом примере, колонка «Company Name» — это атрибут товара. Перетащите ее на группировочную панель, после группировки по «Country», и посмотрите, что получится. Таким образом, из сводной таблицы, содержащей информационный шум, мы получаем информацию в разрезе по товарам, в разрезе их атрибутов. То есть, мы — просто изменили представление данных, не меняя главную и подчиненные таблицы.

p.p.p.s. Если в гриде использовать Band, то заглянув на demos.devexpress.com/...umns/Bands.aspx — там интересный пример отчета по продажам, типа реальные данные как будто для вас :). Сгруппируйте его сначала по Product Name, а потом — по Company Region

И если не учитывать, что при наличии 20 колонок и больше фиг оно поместится на формат А4

Это не проблема, для каждого отчета можно выбрать только нужные колонки, которые поместятся на экране/бумаги.

Вариант с группировкой — у вас физически будет 2 колонки: название товара (ну или ссылка — я абстрактно пишу), и объем продаж по нему. При группировке, все очень красиво распахнется по высоте отчета, потому что все идет в разрезе как в первом случае, но разрез — вертикальный. А если группировать транзакции по товару — так оно еще и сделает консолидацию в одну строчку.

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

Да как обычно:

1) Главная таблица (Sales):
ID, ProductID, RegionID, SaleAmount

2) Подчиненная таблица (Products)
ID, ProductName

3) Подчиненная таблица (Regions)
ID, RegionName

В GridView группируется в разрезе товаров, которые в свою очередь сгруппированы в разрезе регионов (гляньте 2 ссылки что я дал — там все наглядно)

Для обеспечния динамичности аттрибутов(в примере — колонок) рассмотрите вариант следующей структуры данных. Привожу вкратце для вашего примера со списком товаров.
Сущности: Товары, Атрибуты, Значения Атрибутов.
Связи: Товары(1) — Атрибуты(M) — Значения Атрибутов(N).
Таким образом имеем 3 таблицы со связяами 1-ко-многим.
Вместо добавления новой колонки в таблицу Товары, просто добавляете строку в таблицу Аттрибуты со ссылкой на Код Товара, и строку в таблицу Значения Аттрибутов со ссылкой на Код Аттрибута.
Минусы — количество записей может быть слишком большим, сложности с отображением(для классического отображения придется использовать Пивот таблицу по Аттрибутам), дополнительный контроль над целостностью данных.

Плюсы — если у Товара нет атрибута — то и нет пустых значений в таблице, динамичность.

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

Наверное, придется писать инсталляционный скрипт с динамическим DDL-SQL. Но это чревато неприятными последствиями. ORM-ки на такое не очень заточены. Знаю, что XPO как бы может материализовать объектную модель в реляционной базе. На практике как-то не прокатывало...

То, что вам нужно — это pivot table. И ничего больше, ИМХО

msdn.microsoft.com/...y/ms177410.aspx

В случае, если вы работаете с реляционными базами менять структуру таблиц в течении жизни приложения пользователем категорически не рекомендуется. В данном случае, на сколько я понял вам необходимо динамически добавлять свойства к объектам, что необязательно делать на уровне БД.
У вас есть два пути.
1. Если, все же, добавлять подобные свойства на уровне БД, то нужно смотреть в сторону не-реляционных баз (документно-ориентированых, например, или что-нибудь вроде такого

2. Если реляционная база — required, то, как один из способов решения: в таблицу добавляете текстовое поле, например, CustomProperties, в которое складываете сериализированные данные (в XML-формате, просто строкой или как-то по-другому). О плюсах/минусах разных форматов можно почитать в интернете. У такого подхода, конечно же, есть много минусов, но если не ожидается жуткого оверлода системы, то он вполне себя оправдывает. Судя по Вашему профилю, Вы работаете с .Net, поэтому посоветую посмотреть, как работает Umbaco CMS. Поскольку, Вы не указали с чем работаете работаете (с вебом или с десктопом), использовать «Умбряку» советовать не буду, но в исходники залезть будет полезно в любом случае.

Спасибо.

По пункту 2.

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

P.S. Это должен быть веб проект.

Преимущества понятны :) Теперь о минусах.
Во-первых, как для разработчика, пользователю придется давать полный функционал управления базой, начиная от добавление/удаление колонок, навешивание индексов, связи и т.д. и т.п, то есть, фактически, писать свой «SQL Manager».
Во-вторых, об ORM можно забыть, поскольку перекомпилировать ORM после каждого изменения в структуре таблицы/базы как-то не по феншую (думаю, это понятно :) )
В-третьих, очень высокий риск сломать логическую структуру базы.
В-четвертых, (особенно в вебе, при постоянных обращениях) изменяя структуру таблицы/базы «по-живому» можно с легкостью обвалить индексы/потерять данные => свалить всю базу.
В-пятых, поддерживать это будет невозможно, у вас в архитектуре не будет нормальных моделей.
И, причем, это все только в случае, если работать с базой (изменять свойства) будет профессионал, который знает, что он делает. Если администратором усадят обезьянку, то фактически вы дадите этой обезьянке автомат калашникова с подствольным гранатометом.
Ну, и, напоследок, о безопасности.
Разрешать бд-пользователю, от имени которого будет работать web-приложение (IIS-се, например) что-то делать с базой, кроме чтения/добавления/удаления <b>данных</b> т.е. разрешить менять структуру — это такая ДЫРИЩА в секюрити, в которую можно на автобусе заезжать. SQL инъекции гарантированы в больших количествах.

А как написаны те же CRM и CMS системы? Umbraco который был приведен в качестве примера тому подтверждение. Там динамические изменения — обычное дело. Все остальное включая безопасность дело техники. Не надо ничего перекомпилировать и ломать, нужно всего-лишь подойти к вопросу через использование метаданных в качестве расширяемости системы и строгой валидации чего можно а чего нельзя.

В Умбряке все мета-данные хранятся в базе по принципу описанному чуть выше Алексеем, а для оптимизации на старте апликейшена из них генерируется XML-файл, который укладывается в кэш и уже он в дальнейшем используется. Собственно, поэтому я и привел ее в пример. Она не изменяет структуру таблиц «на-лету». И динамические изменения — да, обычное дело, и безопасность, и все остальное, но не на уровне SQL-ля.

Поэтому и не надо ничего перекомпилировать — работаем-то через метаданные, а не с данными напрямую.

Правильно. В том и смысл что изменяется не структура таблиц, а метаданные, которые реализованы как набор таблиц, атрибутов и их связей. При этом используется MS SQL Server в качестве СУБД и никакого гемороя с db_owner-ом и раздачей прав на уровне SQL. СУБД здесь используется только в качестве хранилища данных. Вся логика включая безопасность реализуется на уровне приложения, в данном случае Умбряки. Такой подход к написанию динамических систем весьма стандартен, что может взять автор поста на вооружение.

Да-да, именно это я и имел ввиду :) Жалко, я в том посте про Умбряку не сделал акцент на том, что это еще один из приведенных подходов, воплощенный, так сказать, в жизнь и его можно пощупать.

Инкрементальный поиск по колонке, панель фильтра на несколько колонок, сокрытие записей по кастомным условиям в виде чекбоксов, показ/сокрытие колонок в xtragrid view делаются тупо установкой мышкой его туевой хучи свойств, во время разработки. Не говоря уже о пейджинге, и подгрузке только тех данных, которые отображаются в текущий момент времени, без вытягивания всего мусора. Просто, компоненты от DevExpress для .net ничего лучше в мире нет, на них можно писать левым мизинцем правой ноги, если полностью вкурить их объектную модель. Они из любой гвняшки сделают визуальную конфетку.

Я по привычке использовал бы XTraGrid от DevExpress. Он разве что кофе варить не умеет, потому что и лэйауты с колонками, и представление (Card / Grid) меняется пользователем, или программно, например, скрыть/показать колонки в гриде, с последующим сохранением лэйаута.
Если, конечно, я понял, что имеется ввиду юзер-френдли работа с представлением данных, а не добавление пользователем несуществующих колонок в таблицу базы данных, не на уровне DAL, а на уровне представления данных.
Вот, полюбуйтесь — под веб, и под десктоп поведение поведение одинаковое. И даже есть ломаные инсталляции :)
Так он умеет работать с колонками (это если через драг и дроп с интерфейса)

demos.devexpress.com/...tionWindow.aspx

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

Если говорить категорично, то так делать нельзя, тем более под правами обычного пользователя — оператора. Есть достаточное кол-во вариантов избежать этого. Общий смысл — нужно разделить представление данных, от DAL, а уже в представлении — представляйте как хотите, вплоть до динамического добавления новых экземпляров колонок на уровне класса представления, но менять структуру данных физически динамически — это чревато (почитайте про model-view-controller паттерн)

Сразу новые вопросы:
1. Почему так делать нельзя?

2. Чем это черевато?

Что плохого в том, чтоб дать возможность пользователю настраивать систему под себя?
Некоторые системы багтрекинга это позволяют.

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

Почему так делать нельзя?

Как минимум — пользователю нужно дать права dbOwner. Один пользователь захочет добавить одни колонки, второй — добавить другие, при этом первый пользователь не захочет видеть колонки второго пользователя, а второй пользователь — первого. При апдейте первым пользователем в колонки второго пользователя должно писаться какое-то значение по-умолчанию, если они не допускают NULL — то хана. При апдейте вторым пользователем те же яйца, только в профиль. Какой-то вы должны придумать гвномеханизм, который будет разруливать все известные, а также неизвестные конфликты между пользователями одной таблицы.

Если уж хочется поизвращаться, но только read only — рассмотрите возможность использования view вместо таблиц.

Чем это черевато?

SqlException’ами, потерей данных, потерей целостности данных.

p.s. Тут не каждый DB developer может сделать правильную структуру данных, а вы хотите это переложить на простых смертных пользователей.

Администрирование и настройка отображения данных — отдельный вопрос.
Для простоты можно:
1. Разрешить менять структуру БД только 1 пользователю.
2. Разрешить всем остальным пользователям выбирать (без возможности физического удаления или добавления) колонки, которые они хотят видеть.

Но это действительно отдельный вопрос, его нужно прорабатывать отдельно. Не буду отходить от темы.

Не получится одному пользователю, поскольку придется dbOwner-а придется давать IIS-се. Как вы у себя внутри выстроите систему привилегий — вопрос второй, но главное, что приложение сможет изменять структуру базы. Что, собственно, Струдомпрасцал Вашапраграм и имел ввиду.

Я так понимаю, что схема БД моделируется и материализуется в экземпляре СУБД единожды при инсталляции софта. Только тогда такие требования логичны.

Зачем же сразу в лоб? Никто же не запрещает использовать СУБД только в качестве хранилища данных, а систему безопасности конкретного приложения построить на уровне метаданных в этой самой СУБД, при этом не прибегая к модели безопасности самой СУБД. Проверка прав может выполнятся кастом-провайдером или своим сервисом. В системе может быть некто вроде root, который может создавать/удалять пользователей и раздавать им права, например право на добавление поля(колонки) в определенную сущность(таблицу). Вовсе не обязательно соотносить один-к-одному модель СУБД и модель бизнес-приложения. Исходить из требований это наиболее приоритетная задача, а технологии и способы достижения второстепенная.

www.boxesandarrows.com/...a_based_website

Подписаться на комментарии