Как моделировать вложенную коллекцию с одним основным объектом - PullRequest
0 голосов
/ 27 апреля 2011

Я собираюсь смоделировать в СУБД совещание, которое будет предлагаться несколько раз, но одно будет выбрано как принятое или основное. Что-то вроде:

create table Meeting ( meetingId int );
create table ProposedTime( meetingId int, dateAndTime datetime );

Однако будет интерфейс, в котором пользователь сможет выбрать одно из предложенных времен, и мне нужно сохранить этот выбор.

Я могу придумать два варианта, каждый из которых имеет свои недостатки:

  1. Хранить выбранное предложение в таблице собраний:

    create table Meeting( meetingId int, selectedProposalId int );
    create table ProposedTime( proposalId int PK, meetingId int, dateAndTime datetime );
    

    При таком подходе возможно, что selectedProposalId предназначен для предложения, принадлежащего другому собранию.

  2. Сохранить флажок для выбранного предложения:

    create table Meeting(meetingId int);
    create table ProposedTime( meetingId int, dateAndTime datetime, isSelected bool );
    

    При таком подходе возможно, что два предложения будут помечены как выделенные.

Я знаю, что есть «хаки» для обеспечения целостности (для 2, в MS SQL вы могли бы иметь отфильтрованный уникальный индекс, чтобы убедиться, что выбран только один), но я бы предпочел не связываться с кодом конкретного поставщика.

У меня тоже все хорошо, только на уровне приложения обеспечивается корректность, но все равно остаются открытыми оба варианта.

Что вы, ребята, рекомендуете? Я также открыт для других вариантов, если у кого-то есть какие-либо идеи;)

Примечание: я использую Rails 3, поэтому, если есть предпочтительный способ справиться с этим с помощью ActiveRecord, я бы хотел услышать об этом.

1 Ответ

1 голос
/ 29 апреля 2011

Отличный вопрос. Мне нравится тот факт, что вы оцениваете возможные несоответствия. В этом случае я бы сказал, что первое решение является правильным, с одной небольшой модификацией: первичный ключ ProposedTime должен быть составным первичным ключом, который включает meetingId.

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

Во-вторых, эта зависимость недостаточно выражена при использовании MeetingId в качестве обязательного атрибута. Например, не имеет смысла обновлять поле meetingId предлагаемого времени. «Давайте перенесем 9 утра на другую встречу!». Ввиду того, что meetingId является частью первичного ключа, явно препятствует такого рода бессмысленному обновлению, потому что обновленный первичный ключ - это, по сути, другая вещь.

Наконец, тот факт, что предлагаемое время имеет логически неполный ключ, является одной из первых вещей, с которыми вы столкнулись при попытке использовать его надлежащим образом. Каждое отношение к базе данных, в идеале, должно быть декларативно согласованным. То есть, если вы можете выразить отношение «у львов есть два родителя», один родитель не должен быть белкой. Очевидно, что производительность и ограничения платформы означают, что вы не всегда можете достичь этой цели, но такое несоответствие можно рассматривать как «запах кода», который может потребовать дальнейшего изучения. В вашем случае исправление кажется небольшим и производительным.

tl; dr: добавьте MeetingId к PK предлагаемого времени и перейдите к первому решению.

...