Лучший способ моделирования Customer ↔ Адрес

Каждый Customer имеет физический адрес и необязательный почтовый адрес. Каков ваш предпочтительный способ моделирования этого?

Вариант 1. Customer имеет внешний ключ для Address

   Customer   (id, phys_address_id, mail_address_id)
   Address    (id, street, city, etc.)

Вариант 2. Customer имеет отношение "один ко многим" к Address, которое содержит поле для описания типа адреса

   Customer   (id)
   Address    (id, customer_id, address_type, street, city, etc.)

Вариант 3. Адресная информация де-нормируется и сохраняется в Customer

   Customer   (id, phys_street, phys_city, etc. mail_street, mail_city, etc.)

Одна из моих главных целей - упростить объектно-реляционные сопоставления, поэтому я склоняюсь к первому подходу. Каковы ваши мысли?

Ответ 1

Я склонен к первому подходу по всем обычным причинам нормализации. Этот подход также упрощает очистку данных при рассылке деталей.

Если вы, возможно, собираетесь разрешить несколько адресов (почта, жительство и т.д.) или хотите использовать эффективные даты, рассмотрите этот подход

   Customer   (id, phys_address_id)
   Cust_address_type (cust_id, mail_address_id, address_type, start_date, end_date)
   Address    (id, street, city, etc.)

Ответ 2

Одним из важных фактов, которые вам могут потребоваться (в зависимости от вашего проблемного домена), является то, что люди меняют адреса и могут сообщить вам заранее об изменении их адреса; это, безусловно, справедливо для коммунальных компаний, телекоммуникационных компаний и т.д.

В этом случае вам нужно иметь способ сохранить несколько адресов для клиента с датами действительности, чтобы можно было заранее настроить адрес и автоматически переключиться на правильную точку. Если это требование, то вариация на (2) является единственным разумным способом ее моделирования, например.

Customer (id, ...)
Address (id, customer_id, address_type, valid_from, valid_to)

С другой стороны, если вам не нужно это обслуживать (и вы уверены, что этого не произойдет в будущем), то, вероятно, (1) проще управлять, потому что гораздо проще поддерживать целостность данных, нет проблем с обеспечением наличия только одного адреса того же типа, и объединения становятся проще, поскольку они находятся только в одном поле.

Итак, либо (1), либо (2) в порядке в зависимости от того, нужны ли вам домашние ходы, но я избегаю (3), потому что вы повторяете определение того, какой адрес находится в таблице, и вам нужно будет добавить несколько столбцов, если вы измените внешний вид адреса. Это, возможно, немного более показательно, но, честно говоря, когда вы имеете дело с правильно проиндексированными объединениями в реляционной базе данных, их не так много, и это может быть медленнее в некоторых сценариях, где вам не нужен адрес поскольку размер записи для клиента будет больше.

Ответ 3

Я обнаружил, что то, что кажется первоначально спроектированным дизайнером "клиента", часто ломается, потому что: ранее рассматривая бизнес, когда клиент развивается в отношении отдельных сотрудников как клиентов, или клиент будет изменять/разделять/объединять адреса или бизнес меняет свое имя, но мы все же хотим консолидировать старые и новые показатели производительности, или теперь должен быть расширен адрес доставки и платежный адрес, чтобы включить адрес поддержки, или операторы забыли или допустили одну цель адреса для другого или клиент хочет использовать специальный адрес доставки только временно, или т.д. и т.д.

В результате я вообще отказался от идеи файла основного клиента. Вместо этого имя/информация о компании/адресе никогда не являются основными записями (за исключением таких приложений, как выставление счетов или налоги на имущество, когда конкретный физический адрес никогда не редактируется на другой адрес), это просто поля, обозначающие используемый контакт. AT A PARTICULAR POINT IN ВРЕМЯ, обычно внутри чего-то вроде записи заказа клиента. Каждый заказ клиента привязан к предыдущему и следующему порядку для этого клиента, даже когда клиент меняет свое имя или адрес. Преимущество состоит в том, что все заказы могут консолидироваться/суммироваться/анализироваться по всей истории транзакций клиента, даже если каждый заказ может отличаться от имени или адреса контакта. Это несколько противоречиво, особенно когда вы пытаетесь удовлетворить нормализацию дизайнеров db, но в итоге он становится очень гибким и удобным.

Например, когда клиент X сначала размещает заказ, запись клиента не создается. Вместо этого создается запись заказа клиента, которая содержит необходимую информацию о имени/компании/адресе, действующую на момент заказа. Когда клиент X размещает свой второй заказ, мы не ищем файл клиента, мы ищем файл заказа клиента, а затем копируем/связываем его, чтобы создать свой второй заказ. Если он хочет изменить свое имя/информацию о компании/адресе, отлично, мы просто редактируем эти поля в заказе № 2 и заказ № 1 остается неизменным. Теперь он можно найти в любом варианте (порядок 1 или 2).

Для других соображений при попытке решить, действительно ли две записи клиентов одинаковы, см. http://semaphorecorp.com/mpdd/mpdd.html

Ответ 4

Второй вариант, вероятно, будет таким, каким я буду идти. И по возможности это позволит пользователям добавлять дополнительный адрес "(если вы хотите позволить им это сделать), чтобы они могли переключаться между ними по желанию для доставки и т.д.

Ответ 5

Я предпочел бы # 1. Хорошая нормализация и четко передает намерения. Эта модель также позволяет использовать один и тот же адресный объект (строку) для обоих адресов, что я считаю весьма ценным. Слишком легко заблудиться, слишком много дублируя эту информацию.

Ответ 6

Мы продвигаемся вперед с такой моделью:

Person (id, given_name, family_name, title, suffix, birth_date)
Address (id, culture_id, line1, line2, city, state, zipCode, province, postalCode)
AddressType (id, descriptiveName)
PersonAddress (person_id, address_id, addressType_id, activeDates)

Большинство из них может считать это чрезмерным. Тем не менее, неоспоримой общей темой среди приложений, которые мы разрабатываем, является то, что у них будут некоторые из этих фундаментальных образов - Люди, Организации, Адреса, Телефонные номера и т.д. - и все они хотят объединить их по-разному. Итак, мы строим некоторые обобщения, что мы на 100% уверены, что у нас есть варианты использования.

Таблица адресов будет следовать схеме наследования на основе иерархии для различения адресов на основе культуры; поэтому в адресе Соединенных Штатов будет поле состояния и почтового индекса, но у канадских адресов будет код провинции и почтовый индекс.

Мы используем отдельную таблицу соединений, чтобы "дать" человеку адрес. Это удерживает наши другие сущности - Личность и адрес - свободным от связей с другими сущностями, когда наш опыт таков, как правило, усложняет дело в будущем. Кроме того, гораздо проще подключить объекты Адреса ко многим другим типам сущностей (Люди, Организации и т.д.) И с другой контекстной информацией, связанной с ссылкой (например, activeDates в моем примере).

Ответ 7

При ответе на такие вопросы мне нравится использовать классификацию DDD. Если это Entity, он должен иметь отдельный идентификатор, если это объект значения, он не должен.

Ответ 8

В большинстве случаев, которые я пишу сейчас, каждый клиент имеет одно и только одно физическое местоположение. Это юридическое лицо, являющееся нашим деловым партнером. Поэтому я помещаю улицу, город и т.д. В объект/таблицу клиента. Часто это самая простая вещь, которая работает, и она работает.

Когда необходим дополнительный почтовый адрес, я помещаю его в отдельный объект/таблицу, чтобы не мешать объекту клиента.

Раньше в моей карьере я нормализовался как сумасшедший, имея заказ, ссылающийся на клиента, который ссылается на адрес доставки. Это сделало вещи "чистыми", но медленными и неэффективными. В настоящее время я использую объект заказа, который содержит всю информацию о адресе. Я считаю это более естественным, так как клиент может изменить свой адрес (по умолчанию?), Но адрес отправки отправки в 2007 году должен всегда оставаться неизменным - даже если клиент переезжает в 2008 году.

В настоящее время мы реализуем VerySimpleAddressProtocol в проекте для стандартизации используемых полей.

Ответ 9

Я бы выбрал первый вариант. В этих ситуациях я очень устал от YAGNI (вам это не понадобится). Я не могу сосчитать количество раз, когда я смотрел схемы, которые имели таблицы "один-ко-многим", которые просто "раскалываются", которым много лет. Если вам нужны только два, просто используйте первый вариант; если требование изменится в будущем, измените его.

Ответ 10

Как и во многих случаях: Это зависит.

Если ваши клиенты имеют дело с несколькими адресами, тогда было бы целесообразно отношение "ко многим". Вы можете ввести флаг по адресу, который сигнализирует, если адрес отправлен или выставлен счет, и т.д. Или вы сохраняете разные типы адресов в разных таблицах и имеете несколько отношений один на клиенте.

В тех случаях, когда вам нужно знать только один адрес клиента, почему бы вам выбрать модель для многих? Отношение "один к одному" удовлетворит ваши потребности.

Важно: Denormalize, только если вы столкнулись с проблемами производительности.

Ответ 11

Вариант 3 является слишком строгим, а параметр 1 не может быть расширен, чтобы разрешить другие типы адресов без изменения схемы. Вариант 2, безусловно, является наиболее гибким и, следовательно, лучшим выбором.

Ответ 12

Я бы пошел с вариантом 1. Если вы этого захотите, вы можете немного изменить его, чтобы сохранить историю адресов:

Customer   (id, phys_address_id, mail_address_id)
Address    (id, customer_id, start_dt, end_dt, street, city, etc.)

Если адрес изменится, просто оставьте текущий адрес и добавьте новую запись в таблицу Address. phys_address_id и mail_address_id всегда указывают на текущий адрес.

Таким образом, вы можете сохранить историю адресов, у вас может быть несколько почтовых адресов, хранящихся в базе данных (с по умолчанию в mail_address_id), и если физический адрес и почтовый адрес идентичны, вы просто укажете phys_address_id и mail_address_id в той же записи.

Ответ 13

Хорошая нить. Я потратил некоторое время на то, чтобы рассмотреть наиболее подходящую схему, и я пришел к выводу, что решение quentin-starin является лучшим, за исключением того, что я добавил поля start_date и end_date в качестве своего PersonAddress Таблица. Я также решил добавить заметки, активные и удаленные.

удалено для функциональности мягкого удаления, так как я не хочу потерять трассировку предыдущих адресов, просто удалив запись из таблицы соединений. Я думаю, что это довольно мудро, и что-то другое может захотеть рассмотреть. Если этого не сделать, можно будет пересмотреть бумажные или электронные документы, чтобы попытаться отслеживать адресную информацию (что-то лучше всего избегать).

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

Одна вещь, которую мне хотелось бы услышать, это уникальная индексация таблицы address (опять же, ссылаясь на таблицу с тем же именем в примере quentin-starin. Как вы думаете, это должно быть уникальный индекс должен быть применен (как составной индекс, предположительно, во всех не нулевых/обязательных полях)? Это казалось бы разумным, но может быть трудно остановить дубликаты данных, независимо от того, что почтовые/почтовые индексы не всегда уникальны для одного свойства. Даже если поля страны, провинции и города заполнены из справочных данных (которые они указаны в моей модели), различия в орфографии в адресных строках могут не совпадать. Единственный способ избежать этого может заключаться в том, чтобы запустить один или несколько Запросы БД из полей входящих форм, чтобы узнать, найден ли возможный дубликат. Еще одна мера безопасности - предоставить пользователю возможность выбора из адреса в базе данных, уже связанной с этим человеком, и использовать это для автоматического заполнения. может быть случай, когда вы можете быть только чувством и принять меры предосторожности, чтобы остановить дублирование, но просто принять его может (и, вероятно, произойдет) рано или поздно.

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

11 Независимо от улицы Какой бы город Z1P C0D3

Не следует ли считаться опасным, чтобы одна и та же таблица адрес была присвоена другим сущностям (человеку, компании)? Затем скажите, что пользователь понимает, что одна из этих людей живет на улице 111 Whatever Street, и есть опечатка. Если вы измените этот адрес, он изменит его для обоих объектов. Я бы хотел этого избежать. Мое предположение заключалось бы в том, чтобы модель MVC (в моем случае, PHP Yii2) просматривала существующие записи address, когда создается новый адрес, известный как связанный с этим клиентом (SELECT * FROM address INNER JOIN personaddress ON personaddress.address_id = address.id WHERE personaddress.person_id = {текущий человек, редактируемый идентификатор}) и предоставить пользователю возможность использовать эту запись (как было предложено выше).

Я чувствую, что привязка одного и того же адреса к нескольким различным объектам просто требует неприятностей, поскольку это может быть случай отказа от последующего редактирования записи адрес (непрактично) или риска того, что в будущем редактирование запись может испортить данные, относящиеся к другим объектам, кроме тех, кто редактирует запись адрес.

Мне хотелось бы услышать мысли людей.