Как Вы имеете дело с полиморфизмом в базе данных?

tl; dr: Нет! Функции стрелок и декларации функций / выражения не являются эквивалентными и не могут быть заменены вслепую. Если функция, которую вы хотите заменить, not использует this, arguments и не вызывается с new, тогда да.


Как это часто бывает: это зависит. Функции Arrow имеют другое поведение, чем декларации / выражения функций, поэтому давайте сначала рассмотрим различия:

1. Функции Lexical this и arguments

не имеют собственных привязок this или arguments. Вместо этого эти идентификаторы разрешаются в лексической области, как и любая другая переменная. Это означает, что внутри функции стрелки this и arguments относятся к значениям this и arguments в окружающей среде, функция стрелки определена в (т.е. «снаружи» стрелка )

В случае выражения функции, this относится к объекту, который был создан внутри createObject. В функциональном случае стрелки this относится к this самого createObject.

Это делает функции стрелок полезными, если вам нужно получить доступ к this текущей среды:

// currently common pattern
var that = this;
getData(function(data) {
  that.data = data;
});

// better alternative with arrow functions
getData(data => {
  this.data = data;
});

Обратите внимание, что это также означает, что не можно установить функцию стрелки this с .bind или .call.

Если вы не очень знакомы с this, рассмотрим чтение

2. Функции стрелок не могут быть вызваны с помощью new

ES2015 различает функции, доступные call , и функции, которые являются конструкцией . Если функция конструируется, ее можно вызвать с помощью new, то есть new User(). Если функция является вызываемой, ее можно вызвать без new (т. Е. Вызов нормальной функции).

Функции, созданные посредством деклараций / выражений функций, являются конструктивными и вызываемыми. Функции стрелок (и методы) являются только вызываемыми. class конструкторы только конструктивны.

Если вы пытаетесь вызвать функцию, не вызываемую вызовом, или построить неконструируемую функцию, вы получите ошибку времени выполнения.


Зная это, мы можем указать следующее.

Сменный:

  • Функции, которые не используют this или arguments.
  • Функции, которые используются с .bind(this)

Не сменный:

  • Функции конструктора
  • Функция / методы, добавленные к прототипу (поскольку они обычно используют функции this)
  • Variadic (если они используют arguments (см. ниже))

Давайте рассмотрим это более подробно с помощью ваших примеров:

Функция конструктора

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

Способы прототипа

Скорее всего нет, потому что методы прототипа обычно используют this для доступа к экземпляру. Если они не используют this, вы можете его заменить. Однако, если вы в первую очередь заботитесь о сжатом синтаксисе, используйте class с его синтаксисом сжатого метода:

class User {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

Методы объекта

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

const obj = {
  getName() {
    // ...
  },
};

Обратные вызовы

Это зависит. Вы должны обязательно заменить его, если вы наложили внешний this или используете .bind(this):

// old
setTimeout(function() {
  // ...
}.bind(this), 500);

// new
setTimeout(() => {
  // ...
}, 500);

Но: Если код, вызывающий обратный вызов, явно устанавливает this на определенное значение , как это часто бывает с обработчиками событий, особенно с jQuery, и обратный вызов использует this (или arguments), вы не можете использовать функцию стрелки!

Variadic функции

Поскольку функции стрелок не имеют собственных arguments, вы не можете просто заменить их функцией стрелки. Однако ES2015 вводит альтернативу использованию arguments: параметр rest .

// old
function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// new
const sum = (...args) => {
  // ...
};

Связанный вопрос:

Дополнительные ресурсы:

49
задан Charles Menguy 25 April 2012 в 15:47
поделиться

11 ответов

Обычно существует три способа отобразить объектное наследование на таблицы базы данных.

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

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

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

то, Что Вы хотите использовать, зависит, конечно, от Вашей ситуации. Ни одно из решений не прекрасно, таким образом, необходимо взвесить за и против.

41
ответ дан approxiblue 7 November 2019 в 11:29
поделиться

Смотрите на Martin Fowler Шаблоны Архитектуры приложений для предприятия :

  • Единственное Наследование Таблицы :

    При отображении на реляционную базу данных, мы пытаемся минимизировать соединения, которые могут быстро возрасти при обработке структуры наследования в нескольких таблицах. Единственное Наследование Таблицы отображает все поля всех классов структуры наследования в единственную таблицу.

  • Наследование Таблицы Класса :

    Вы хотите структуры базы данных, которые отображаются ясно на объекты и позволяют ссылки где угодно в структуре наследования. Наследование Таблицы класса поддерживает это при помощи одной таблицы базы данных в классе в структуре наследования.

  • Конкретное Наследование Таблицы :

    Размышление о таблицах с точки зрения экземпляра объекта, разумный маршрут должен взять каждый объект в памяти и отобразить его на строку единой базы данных. Это подразумевает Конкретное Наследование Таблицы, где существует таблица для каждого реального класса в иерархии наследования.

50
ответ дан approxiblue 7 November 2019 в 11:29
поделиться

Если бы Пользователь, Человек и Особенный человек, у всех есть те же внешние ключи, то у меня была бы единственная таблица. Добавьте столбец под названием Тип, который вынужден быть Пользователем, Человеком или Особенным человеком. Тогда на основе значения Типа имеют ограничения на другие дополнительные столбцы.

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

6
ответ дан Mat Roberts 7 November 2019 в 11:29
поделиться

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

у меня недавно был уникальный случай полиморфизма дб в проекте. Мы имели между 60 - 120 возможными классами, каждым с его собственным набором 30 - 40 уникальных атрибутов и приблизительно 10 - 12 общих атрибутов на всех классах. Мы решили пойти путем SQL-XML и закончили с единственной таблицей. Что-то как:

PERSON (personid,persontype, name,address, phone, XMLOtherProperties)

содержащий всю общую собственность как столбцы и затем большой набор свойств XML. Уровень ORM был тогда ответственен за чтение/запись соответствующих свойств от XMLOtherProperties. Немного как:

 public string StrangeProperty
{
get { return XMLPropertyBag["StrangeProperty"];}
set { XMLPropertyBag["StrangeProperty"]= value;}
}

(мы закончили тем, что отобразили xml столбец как Hastable, а не документ XML, но можно использовать любые иски DAL лучше всего)

Он не собирается получать любые премии дизайна, но он будет работать, если у Вас будет большое (или неизвестный) количество возможных классов. И в SQL2005 можно все еще использовать XPath в SQL-запросах для выбора строк на основе некоторого свойства, которое хранится как XML.. это - просто маленькая потеря производительности для принятия.

5
ответ дан Radu094 7 November 2019 в 11:29
поделиться

Что я собираюсь сказать, здесь собирается отправить архитекторов базы данных в истерики, но сюда идет:

Рассматривают базу данных представление как эквивалент интерфейсного определения. И таблица является эквивалентом класса.

Так в Вашем примере, все 3 класса человека реализуют интерфейс IPerson. Таким образом, у Вас есть 3 таблицы - один для каждого 'Пользователя', 'Человека' и 'SpecialPerson'.

Тогда имеют представление 'PersonView' или независимо от того, что это выбирает общую собственность (как определено Вашим 'интерфейсом') от всех 3 таблиц в единственное представление. Используйте столбец 'PersonType' в этом представлении для хранения фактического типа сохраненного человека.

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

5
ответ дан HS. 7 November 2019 в 11:29
поделиться

Существует три основных стратегии обработки наследования в реляционной базе данных и многих более сложных/сделанных на заказ альтернатив в зависимости от Ваших точных потребностей.

  • Таблица на иерархию классов. Одна таблица для целой иерархии.
  • Таблица на подкласс. Отдельная таблица составлена для каждого sub класса с ассоциацией 0-1 между разделенными на подклассы таблицами.
  • Таблица на реальный класс. Единственная таблица составлена для каждого реального класса.

Каждый из этих appoaches поднимает свои собственные вопросы о нормализации, коде доступа к данным и хранении данных, хотя мое персональное предпочтение должно использовать таблица на подкласс , если нет реальное исполнение или структурная причина пойти с одним из альтернативы.

4
ответ дан Ubiguchi 7 November 2019 в 11:29
поделиться

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

главная причина для того, чтобы сделать его этот путь состоит в том, что это тогда становится намного более логически последовательным, и Вы не заканчиваете с большим количеством полей, которые являются ПУСТЫМИ и бессмысленными для той конкретной записи. Этот метод также делает намного более легким добавить дополнительные поля к подтипам, поскольку Вы выполняете итерации своего процесса проектирования.

Это действительно добавляет, что оборотная сторона добавления СОЕДИНЯЕТ с Вашими запросами, которые могут повлиять на производительность, но я почти всегда иду с идеальным дизайном сначала, и затем надеюсь оптимизировать позже, если это оказывается необходимым. Несколько раз я пошел 'оптимальным' путем сначала, я почти всегда сожалел о нем позже.

, Таким образом, мой дизайн был бы чем-то как

ЧЕЛОВЕК (personid, имя, адрес, телефон...)

SPECIALPERSON (personid ССЫЛОЧНЫЙ ЧЕЛОВЕК (personid), дополнительные поля...)

ПОЛЬЗОВАТЕЛЬ (personid ССЫЛОЧНЫЙ ЧЕЛОВЕК (personid), имя пользователя, encryptedpassword, дополнительные поля...)

, Вы могли также создать ПРЕДСТАВЛЕНИЯ позже, который агрегировал супертип и подтип, если это необходимо.

один дефект в этом подходе - то, при нахождении в большой степени подтипов связанными с супертипом particulare. Нет никакого легкого ответа на это первое, что пришло на ум, Вы могли отследить его программно при необходимости, или иначе выполнить soem глобальные запросы и кэшировать результаты. Это будет действительно зависеть от приложения.

4
ответ дан kaybenleroll 7 November 2019 в 11:29
поделиться

Я сказал бы, что, в зависимости от того, что дифференцирует Человека и Особенного человека, Вы, вероятно, не хотите полиморфизм для этой задачи.

я составил бы таблицу User, таблица Person, которая имеет nullable поле внешнего ключа Пользователю (т.е., Человек может быть Пользователем, но не имеет к).
Тогда я сделал бы таблицу SpecialPerson, которая касается таблицы Person с любыми дополнительными полями в нем. Если запись присутствует в SpecialPerson для данного Человека. Идентификатор, he/she/it является особенным человеком.

3
ответ дан Lars Mæhlum 7 November 2019 в 11:29
поделиться

да, я также рассмотрел бы TypeID наряду с таблицей PersonType, если возможно, что будет больше типов. Однако, если существуют только 3, которые не должны быть NEC.

1
ответ дан Sara Chipps 7 November 2019 в 11:29
поделиться

Лично, я сохранил бы все эти различные пользовательские классы в единственной таблице. У Вас может тогда или быть поле, которое хранит значение 'Типа', или можно подразумевать, с каким человеком Вы имеете дело тем, в чем поля заполнены. Например, если UserID является ПУСТЫМ, то эта запись не является Пользователем.

Вы могли связаться с другими таблицами с помощью одной для one-none типа соединения, но тогда в каждом запросе Вы будете добавлять дополнительные соединения.

первый метод также поддерживается LINQ к SQL, если Вы решаете спуститься по тому маршруту (они называют его 'Таблицей На Иерархию' или 'TPH').

-1
ответ дан Chris Roberts 7 November 2019 в 11:29
поделиться

В прошлом я сделал его точно, как Вы предполагаете - имеют таблицу Person для общего материала, тогда SpecialPerson, связанный для производного класса. Однако я заново продумал это, поскольку Linq2Sql хочет иметь поле в той же таблице, указывают на различие. Я не посмотрел на модель объекта слишком много, хотя - вполне уверенный, который позволяет другой метод.

0
ответ дан Danimal 7 November 2019 в 11:29
поделиться