Структура проектирования/нормализации базы данных должна содержать И, ИЛИ, необязательные элементы и их взаимосвязи.

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

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


Простой пример.
Курс на 60 кредитов включает несколько обязательных модулей, которые составляют 40 кредитов. Остается выбрать 20 кредитов из группы дополнительных модулей. (Сами модули могут содержать разное количество кредитов). Эффективно; ('Mandatory module 1' AND 'Mandatory module 2'... AND'Mandatory module N') AND (40 credits from 'optional modules'),

И и ИЛИ:
Когда я говорю о модулях выше, это может быть один модуль или «Модуль x ИЛИ Модуль Y», то есть в обязательном разделе. (эти модули, очевидно, должны иметь одинаковый кредитный вес). Или в необязательном разделе могут быть отдельные модули, или даже один из вариантов может быть чем-то вроде "module x AND module y".

Варианты.
Учащимся, возможно, придется пройти обязательные модули плюс один из n вариантов, которые могут содержать или не содержать И, ИЛИ, а также обязательные и необязательные разделы; т. е. «Вариант» имеет все атрибуты общего выбора модулей курса. Раздел «Параметры» будет объединяться по И или ИЛИ с другими разделами, такими как обязательные или необязательные; то есть обязательные модули «плюс один из следующих вариантов». По сути, раздел опций - это просто 'Option 1' OR 'Option 2'... OR 'Option N'.


Проблема заключается в том, как сохранить все отношения И и ИЛИ, когда операнд может быть другой операцией И/ИЛИ или одним модулем, и отслеживать количество кредитов, разрешенных для каждого выбора; например «20 кредитов из следующего:» (группа дополнительных модулей).


person Adam Lynch    schedule 23.12.2011    source источник
comment
Каждый модуль составляет кредит?   -  person Jrod    schedule 23.12.2011
comment
Да. Самый низкий - 5-ти кредитный модуль. Максимальный модуль, который я видел, это 15-ти кредитный модуль, но может быть и более взвешенный модуль.   -  person Adam Lynch    schedule 23.12.2011
comment
Где ваш фактический код для этой проблемы? Потому что все, что я вижу здесь, это OO вертеть большим пальцем.   -  person jcolebrand    schedule 11.01.2012
comment
Было бы неплохо, если бы в ответах были схемы...   -  person C. Ross    schedule 11.01.2012


Ответы (5)


Дизайн довольно прост, вам просто нужна рекурсивная «групповая» таблица с ограничениями.

Course
- ID
- Title
- Credits

Course_Group
- CourseID
- GroupID

Group
- ID
- GroupID
- Description
- AtLeastNSelections
- AtLeastNCredits

Group_Module
- GroupID
- ModuleID

Module
- ID
- Title
- Credits

Примерная структура будет

Course: 1, "Math Major", 60
Group: 1, NULL, "Core Modules", 2, 40
Course_Group: 1, 1
    Group: 2, 1, "Required (5) Core Modules", 5, 25
    Course_Group: 1, 1
    Group_Module: (1, 1), (1, 2), (1, 3), (1, 4), (1, 5)
        Module: 1, "Calculus I", 5
        Module: 2, "Calculus II", 5
        Module: 3, "Calculus III", 5
        Module: 4, "Stats I", 5
        Module: 5, "Stats II", 5
    Group: 3, 1, "Required (3) Of (N) Modules", 3, 15
    Course_Group: 1, 3
    Group_Module: (3, 6), (3, 7), (3, 8), (3, 9), (3, 10)
        Module: 6, "Number Theory", 5
        Module: 7, "Bridge Adv. Math", 5
        Module: 8, "Calculus IV", 5
        Module: 9, "Stats III", 5
        Module: 10, "Finite Math", 5
Group: 4, NULL, "Secondary Modules", 1, 20
Course_Group: 1, 4
    Group: 5, 4, "Comp. Sci.", 2, 0
    Course_Group: 1, 5
    Group_Module: (5, 11), (5, 12), (5, 13), (5, 14), (5, 15), (5, 16)
        Module: 11, "Math in Hardware", 4
        Module: 12, "Math in Software", 4
        Module: 13, "Programming 101", 4
        Module: 14, "Algorithms 101", 4
        Module: 15, "Programming I", 5
        Module: 16, "Programming II", 5
    Group: 6, 4, "Physics", 0, 8
    Course_Group: 1, 6
    Group_Module: (6, 17), (6, 18), (6, 19), (6, 20)
        Module: 17, "Physics Mechanics", 4
        Module: 18, "Physics Thermodynamics", 4
        Module: 19, "Physics Magnetism", 5
        Module: 20, "Physics Theoretical", 5
    Group: 7, 4, "Gen. Ed.", 0, 0
    Course_Group: 1, 7
    Group_Module: (7, 21), (7, 22), (7, 23), (7, 24)
        Module: 21, "Business Writing", 3
        Module: 22, "Ethics", 3
        Module: 23, "Aesthetics", 3
        Module: 24, "Graphic Design", 3

Краткий обзор... в курсе "Math Major" есть две группы: "Основные модули" и "Второстепенные модули". «Основные модули» требуют НЕ МЕНЕЕ 2 детей и НЕ МЕНЕЕ 40 кредитов. «Вторичные модули» требуют МИНИМУМ 1 ребенка И МИНИМУМ 20 кредитов.

Вы можете видеть, что ограничения групп в разделе «Основные модули» более строгие, чем ограничения групп в разделе «Вторичные модули».

Вывод приведенной выше структуры примера будет выглядеть примерно так.

SELECT c.Title, g.Description, m.Title FROM Course c
 INNER JOIN Course_Group cg ON c.ID = cg.CourseID
 INNER JOIN Group g ON cg.GroupID = g.ID
 INNER JOIN Group_Module gm ON g.ID = gm.GroupID
 INNER JOIN Module m ON gm.ModuleID = m.ID
WHERE c.ID = 1
ORDER BY g.GroupID, g.ID, m.Title  

Итак, если у вас есть курс и модули, вы можете получить все группы для курса из таблицы Course_Group и узнать, к какой группе принадлежат модули, из таблицы Group_Module. После того, как у вас есть модули в их группах, вы можете проверить ограничения группы AtLeastNSelections AND AtLeastNCredits, проходя по цепочке родительских элементов Group.GroupID, пока не дойдете до Group.GroupID = NULL.

person Louis Ricci    schedule 17.01.2012
comment
Итак, Group.GroupID ссылается на Group.ID, да? - person Adam Lynch; 18.01.2012
comment
@ Адам Линч - Да, я обычно стараюсь сохранять FK / ссылки как таблицу + столбец для имен. - person Louis Ricci; 18.01.2012

Очень простой первый подход будет использовать всего 4 таблицы:

TABLE Course 
( CourseId 
, Title 
, TotalCredits 
, ... other stuff
, PRIMARY KEY (CourseId)
) ;

TABLE Module 
( ModuleId 
, Description 
, Hours
, Credits
, ... other stuff
, PRIMARY KEY (ModuleId)
) ;

и комбинации, разрешенные через эти 2:

TABLE Course_Module 
( CourseID                 --- for this course
, ModuleID                 --- this module is allowed (optional or mandatory)
, PRIMARY KEY (CourseID, ModuleId)
, FOREIGN KEY (CourseId) 
    REFERENCES Course (CourseId)
, FOREIGN KEY (ModuleId)
    REFERENCES Module (ModuleId)
) ;

TABLE Course_MandatoryModule 
( CourseID                  --- for this course
, ModuleID                  --- this module is mandatory
, PRIMARY KEY (CourseID, ModuleId)
, FOREIGN KEY (CourseID, ModuleId)
    REFERENCES Course_Module (CourseID, ModuleId)
) ;

Теперь, если ваши допустимые комбинации модулей и курсов более сложны, как следует из вашего описания, вместо таблиц Course_Module и Course_MandatoryModule вы можете определить сложную иерархическую модель:

Курсы:

TABLE Course                        --- same as previous model
( CourseId 
, Title 
, TotalCredits 
, ... other stuff
, PRIMARY KEY (CourseId)
) ;

Модули и группы (модули):

TABLE ModuleEntity                  --- the supertype for both
( ModuleEntityId                    --- modules and group of modules
, PRIMARY KEY (ModuleEntityId)
) ;

TABLE Module                        --- subtype
( ModuleId 
, Description 
, Hours
, Credits
, ... other stuff
, PRIMARY KEY (ModuleId)
, FOREIGN KEY (ModuleId) 
    REFERENCES ModuleEntity (ModuleEntityId)
) ;

TABLE ModuleGroup                  --- group of modules
( ModuleGroupId                    --- subtype of the supertype (entity)
, GroupDescription        
, PRIMARY KEY (ModuleGroupId)
, FOREIGN KEY (ModuleGroupId) 
    REFERENCES ModuleEntity (ModuleEntityId)
) ;

и отношения (модуль принадлежит к группе):

TABLE Module_in_Group  
( ModuleEntityId               --- this module or group
, ModuleGroupId                --- is in this group
, PRIMARY KEY (ModuleEntityId, ModuleGroupID)
, FOREIGN KEY (ModuleEntityId)
    REFERENCES ModuleEntity (ModuleEntityId)
, FOREIGN KEY (ModuleGroupId)
    REFERENCES ModuleGroup (ModuleGroupId)
) ;

и (наконец) курс может иметь группу модулей:

TABLE Course_ModuleGroup
( CourseId                 --- for this course
, ModuleGroupId            --- this module group is allowed
, PRIMARY KEY (CourseID, ModuleGroupId)
, FOREIGN KEY (CourseId) 
    REFERENCES Course (CourseId)
, FOREIGN KEY (ModuleGroupId)
    REFERENCES ModuleGroup (ModuleGroupId)
) ;
person ypercubeᵀᴹ    schedule 23.12.2011
comment
Хорошо, но как мне сохранить группу внутри группы? Насколько я понимаю, для каждого уровня в вашем решении должно быть еще несколько таблиц? - person Adam Lynch; 23.12.2011
comment
Нет, об этом позаботится таблица Module_in_Group. Вы даже можете иметь группу внутри себя с этой моделью. Или цикл group A in B, group B in C, group C in A, которого вы явно не хотите! - person ypercubeᵀᴹ; 23.12.2011
comment
Спасибо за ответ. Теперь, прежде чем я приму это, для чего GroupDescription в ModuleGroup? Это просто место для текстового описания/имени? если да, то как я могу обрабатывать разные типы группировки в вашем ответе? Например. один тип группы заключается в том, что я должен выбрать количество кредитов из группы, другой - я выбираю их все (И) и третий - я выбираю один (ИЛИ и варианты). Ответ на это был бы очень признателен! - person Adam Lynch; 06.01.2012

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

  • Затем можно определить «основные» параметры, запросив в этой таблице все параметры с «нулевыми» родителями.

  • Отношения «и-или» могут быть реализованы отдельной таблицей «набор опций», где первичный ключ относится к «опции». Таблицы набора опций с нулевыми ссылками на самих себя являются «корневой» точкой для определения опций курса. С этого момента вы будете выбирать записи с набором опций с parent = root. Это будет первый «уровень» опций. Что-то будет обязательным, что-то нет. Чтобы выразить это, вам нужно будет иметь логический атрибут в таблице набора параметров в качестве флага. Таким образом, каждый набор параметров определяется в терминах меньших наборов параметров. Конечно, в конце концов, как только вы доберетесь до сути, ваш набор опций в какой-то момент определит фактический класс.

Я бы предположил, что это можно гораздо эффективнее смоделировать в JSON или XML, поскольку эти структуры данных поддерживают иерархии гораздо более выразительным образом.

person jayunit100    schedule 23.12.2011

Вероятно, вы можете сделать что-то вроде этого:

TABLE course_definition (
    ID int,
    num_mandatory_sections int,
    mandatory_hours int,
    num_optional_modules int,
    optional_hours int,
);

TABLE modules (
    ID int,
    Description varchar(max),
    hours int,
    ....
);

TABLE course (
    Course_ID int FOREIGN KEY (course_definition.id),
    module_id int FOREIGN KEY (modules.id)
);

TABLE course_module_relationship (
     Course_ID int FOREIGN KEY (course_definition.id),
     module_ID int foreign key (modules.id),
     Requirement_flag ENUM ("MANDATORY", "OPTIONAL")
);

TABLE Student_to_course (
     Student_ID int,
     Course_ID int foreign key (course_definition.id)
);

TABLE Student_to_module (
     Student_ID int,
     Module_ID int FOREIGN KEY (module.id)
);

Если вам действительно нужно иметь возможность создавать групповые модули, то есть один модуль, созданный из нескольких других модулей, тогда в таблице module должно быть поле флага:

group_module boolean

и следует добавить следующую таблицу:

TABLE module_groupings (
    group_module_ID int foreign key (module.id)
    dependant_module_id int foreign key (module.id)
);

Это скорее псевдокод, но вы поняли идею. Таблица course и course_module_relationship не будет иметь ключей и хранить ваши отношения, поскольку они могут быть многие ко многим, насколько я понимаю проблему. Таким образом, в основном код, который будет читать процесс выбора, должен будет проверить, соответствует ли он критериям для course_definition.

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

person Karlson    schedule 23.12.2011
comment
Но может ли это быть рекурсивным? т. е. параметры аналогичны общей модели и могут иметь обязательные разделы и т. д. внутри них - person Adam Lynch; 23.12.2011
comment
Модули в зависимости от модулей? Я понимаю вашу проблему так, что вы в основном пытаетесь реализовать учебную программу колледжа в базе данных, и в этом случае курс или модули являются атомами, из которых вы пытаетесь построить. Но если вам нужна предварительная таблица, это легко сделать. - person Karlson; 23.12.2011
comment
Какая? Пример: учащимся может потребоваться пройти 4 обязательных модуля плюс 1 из 3 вариантов (каждый вариант включает 2 обязательных модуля и группу модулей, из которых необходимо выбрать 10 кредитов) плюс 20 кредитов из группы дополнительных модулей. - person Adam Lynch; 23.12.2011
comment
Я не уверен, что следую требованиям, но если у вас есть отдельные модули и групповые модули (группа отдельных модулей), я добавил код для описания этих отношений. Идея состоит в том, чтобы разбить данные на самые атомарные части, а затем иметь таблицу, которая устанавливает отношения между ними. - person Karlson; 23.12.2011

Система качества производства, использующая и/или (например, ваша система), которую вы можете просмотреть бесплатно, называется entlib 5.0 Security block. http://entlib.codeplex.com/

Каждое правило извлекается по имени, чтобы получить полное выражение. Команда шаблонов и практики создала собственный короткий DSL. для выражения, чтобы избежать усложнения структуры xml/db.

это внутри практических лабораторных упражнений ex02 app.config. Для хранения правил внутри базы данных вам потребуется реализовать собственный AuthorizationRuleProvider.

R: = имя роли; У: = имя пользователя

  <securityConfiguration defaultAuthorizationInstance="RuleProvider"
defaultSecurityCacheInstance="">
<authorizationProviders>
  <add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security"
    name="RuleProvider">
    <rules>
      <add expression="R:Employee OR R:Developer OR R:Manager" name="Raise Bug" />
      <add expression="R:Manager" name="Assign Bug" />
      <add expression="R:Developer OR R:Manager" name="Resolve Bug" />
    </rules>
  </add>
</authorizationProviders>

dev usage

    public static AssignBug Create()
    {
        // TODO: Check Authorization
        if (!SecurityHelper.Authorized(AuthRule.Assign))
        {
            throw new SecurityException();
        }

        return new AssignBug();
    }

Хотя это и не немедленный ответ, я думаю, что это хороший пример того, как реализовать системы, основанные на выражениях правил.

person Leblanc Meneses    schedule 16.01.2012