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

Наследование типа public

Открытое наследование является одним из наиболее используемых типов наследования. Очень редко вы увидите или будете использовать другие типы, поэтому основной упор следует сделать на понимание именно этого типа наследования. К счастью, открытое наследование является самым легким и простым из всех типов. Когда вы открыто наследуете родительский класс, то унаследованные public-члены остаются public, унаследованные protected-члены остаются protected, а унаследованные private-члены остаются недоступными для дочернего класса. Ничего не меняется.

Спецификатор доступа в родительском классе Спецификатор доступа при наследовании типа public в дочернем классе
public public
private Недоступен
protected protected

Например:

class Parent
{
public:
int m_public;
private:
int m_private;
protected:
int m_protected;
};

class Pub: public Parent // открытое наследование
{
// Открытое наследование означает, что:
// — public-члены остаются public в дочернем классе;
// — protected-члены остаются protected в дочернем классе;
// — private-члены остаются недоступными в дочернем классе.
public:
Pub()
{
m_public = 1; // разрешено: доступ к m_public открыт
m_private = 2; // запрещено: доступ к m_private в дочернем классе из родительского класса закрыт
m_protected = 3; // разрешено: доступ к m_protected в дочернем классе из родительского класса открыт
}
};

int main()
{
Parent parent;
parent.m_public = 1; // разрешено: m_public доступен извне через родительский класс
parent.m_private = 2; // запрещено: m_private недоступен извне через родительский класс
parent.m_protected = 3; // запрещено: m_protected недоступен извне через родительский класс

Pub pub;
pub.m_public = 1; // разрешено: m_public доступен извне через дочерний класс
pub.m_private = 2; // запрещено: m_private недоступен извне через дочерний класс
pub.m_protected = 3; // запрещено: m_protected недоступен извне через дочерний класс
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

classParent

{

public

intm_public;

private

intm_private;

protected

intm_protected;

};

classPubpublicParent// открытое наследование

{

// Открытое наследование означает, что:

// — public-члены остаются public в дочернем классе;

// — protected-члены остаются protected в дочернем классе;

// — private-члены остаются недоступными в дочернем классе.

public

Pub()

{

m_public=1;// разрешено: доступ к m_public открыт

m_private=2;// запрещено: доступ к m_private в дочернем классе из родительского класса закрыт

m_protected=3;// разрешено: доступ к m_protected в дочернем классе из родительского класса открыт

}

};

intmain()

{

Parentparent;

parent.m_public=1;// разрешено: m_public доступен извне через родительский класс

parent.m_private=2;// запрещено: m_private недоступен извне через родительский класс

parent.m_protected=3;// запрещено: m_protected недоступен извне через родительский класс

Pub pub;

pub.m_public=1;// разрешено: m_public доступен извне через дочерний класс

pub.m_private=2;// запрещено: m_private недоступен извне через дочерний класс

pub.m_protected=3;// запрещено: m_protected недоступен извне через дочерний класс

}

Правило: Используйте открытое наследование, если у вас нет веских причин делать иначе.

See also

  • ObjectPlayground.com — A really useful interactive learning site for learning about objects.
  • Secrets of the JavaScript Ninja, Chapter 6 — A good book on advanced JavaScript concepts and techniques, by John Resig and Bear Bibeault. Chapter 6 covers aspects of prototypes and inheritance really well; you can probably track down a print or online copy fairly easily.
  • — Part of Kyle Simpson’s excellent series of JavaScript manuals, Chapter 5 in particular looks at prototypes in much more detail than we do here. We’ve presented a simplified view in this series of articles aimed at beginners, whereas Kyle goes into great depth and provides a more complex but more accurate picture.
  • Назад
  • Обзор: Objects
  • Далее

Итак, когда мне следует использовать спецификатор доступа protected?

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

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

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

Модификатор доступа protected

Для начала нужно знать об доступе protected, который является неотъемлемой частью наследования. protected — это модификатор доступа, который работает как private, но распространяется также на свойства предка. На рисунки ниже можно увидеть какими доступами можно пользоваться.

class Animals {
protected:
int zebras;
};

class Dog : public Animals {
int counter_zebras () {
return zebras;
}
};

1
2
3
4
5
6
7
8
9
10

classAnimals{

protected

intzebras;

};

classDogpublicAnimals{

intcounter_zebras(){

returnzebras;

}

};

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

СВОЙСТВА

  • PROPERTY_ID (первичный ключ)
  • POLICY_ID (внешний ключ)

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

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

Я не понимаю, что вас не устраивает в этом подходе — это то, как вы храните данные, сохраняя при этом ссылочную целостность, а не дублируя данные. Термин «нормализованный» …

Поскольку SQL основан на SET, он довольно чужд концепциям процедурного / объектно-ориентированного программирования и требует, чтобы код переходил из одной области в другую. Часто рассматриваются ORM, но они не работают в больших объемных сложных системах.

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

Кроме того, в решении Daniel Vassallo, если вы используете SQL Server 2016+, есть еще одно решение, которое я использовал в некоторых случаях без значительной потери производительности.

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

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

1 Интересная идея. Я еще не использовал JSON в SQL Server, но часто использую его в других местах

Спасибо за внимание

Другой способ сделать это — использовать составная часть. Например:

Таким образом, можно определить наследование между таблицами.

  • Поддерживают ли другие БД Помимо PostgreSQL ? MySQL например ?
  • 1 @giannischristofakis: MySQL — это только реляционная база данных, тогда как Postgres — это объектно-реляционная база данных. Итак, никакой MySQL этого не поддерживает. Фактически, я думаю, что Postgres — единственная существующая СУБД, которая поддерживает этот тип наследования.
  • 3 @ marco-paulo-ollivier, вопрос OP касается SQL Server, поэтому я не понимаю, почему вы предоставляете решение, которое работает только с Postgres. Очевидно, не решая проблему.
  • 2 @mapto этот вопрос стал чем-то вроде «как сделать объектно-ориентированное наследование в базе данных» целью обманки; что изначально речь шла о sql server, вероятно, теперь не имеет значения

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

Кроме того, я не знаю, какую версию SQL Server вы используете, но в 2008+ Sparse Columns помогает оптимизировать производительность в ситуациях, когда многие значения в столбце будут NULL.

В конечном итоге вам придется решить, насколько «похожи» разделы политики. Если они существенно не отличаются, я думаю, что более нормализованное решение может доставить больше проблем, чем оно того стоит … но только вы можете сделать это. :)

  • Будет слишком много информации для представления всей Политики за один раз, поэтому нет необходимости извлекать всю запись целиком. Думаю, это 2005 год, хотя в других проектах я использовал редкость 2008 года.
  • Откуда появился термин «единая таблица разделов»? Google почти не показывает результатов для этого, и здесь уже достаточно запутанных терминов.

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

Посмотрите ответ, который я дал здесь

Свободное однозначное сопоставление NHibernate с синтетическими ключами

Рекомендуем

Сочетание клавиш IntelliJ для конкретной конфигурации запуска

2021

Math.random () объяснение

2021

JAVA

Наследование типа private

При закрытом наследовании все члены родительского класса наследуются как закрытые. Это означает, что private-члены остаются недоступными, а protected- и public-члены становятся private в дочернем классе.

Обратите внимание, это не влияет на то, как дочерний класс получает доступ к членам родительского класса! Это влияет только на то, как другими объектами осуществляется доступ к этим членам через дочерний класс:

class Parent
{
public:
int m_public;
private:
int m_private;
protected:
int m_protected;
};

class Priv: private Parent // закрытое наследование
{
// Закрытое наследование означает, что:
// — public-члены становятся private (m_public теперь private) в дочернем классе;
// — protected-члены становятся private (m_protected теперь private) в дочернем классе;
// — private-члены остаются недоступными (m_private недоступен) в дочернем классе.
public:
Priv()
{
m_public = 1; // разрешено: m_public теперь private в Priv
m_private = 2; // запрещено: дочерние классы не имеют доступ к закрытым членам родительского класса
m_protected = 3; // разрешено: m_protected теперь private в Priv
}
};

int main()
{
Parent parent;
parent.m_public = 1; // разрешено: m_public доступен извне через родительский класс
parent.m_private = 2; // запрещено: m_private недоступен извне через родительский класс
parent.m_protected = 3; // запрещено: m_protected недоступен извне через родительский класс

Priv priv;
priv.m_public = 1; // запрещено: m_public недоступен извне через дочерний класс
priv.m_private = 2; // запрещено: m_private недоступен извне через дочерний класс
priv.m_protected = 3; // запрещено: m_protected недоступен извне через дочерний класс
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

classParent

{

public

intm_public;

private

intm_private;

protected

intm_protected;

};

classPrivprivateParent// закрытое наследование

{

// Закрытое наследование означает, что:

// — public-члены становятся private (m_public теперь private) в дочернем классе;

// — protected-члены становятся private (m_protected теперь private) в дочернем классе;

// — private-члены остаются недоступными (m_private недоступен) в дочернем классе.

public

Priv()

{

m_public=1;// разрешено: m_public теперь private в Priv

m_private=2;// запрещено: дочерние классы не имеют доступ к закрытым членам родительского класса

m_protected=3;// разрешено: m_protected теперь private в Priv

}

};

intmain()

{

Parentparent;

parent.m_public=1;// разрешено: m_public доступен извне через родительский класс

parent.m_private=2;// запрещено: m_private недоступен извне через родительский класс

parent.m_protected=3;// запрещено: m_protected недоступен извне через родительский класс

Priv priv;

priv.m_public=1;// запрещено: m_public недоступен извне через дочерний класс

priv.m_private=2;// запрещено: m_private недоступен извне через дочерний класс

priv.m_protected=3;// запрещено: m_protected недоступен извне через дочерний класс

}

Итого:

Спецификатор доступа в родительском классе Спецификатор доступа при наследовании типа private в дочернем классе
public private
private Недоступен
protected private

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

На практике наследование типа private используется редко.

Наследование Одной Таблицы (она же Таблица Наследования Иерархии):

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

Сохранение простоты дизайна-это плюс, но основные проблемы с этим подходом заключаются в следующем:

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

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

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

Наследование с цепочкой прототипов

Объекты в JavaScript — динамические «контейнеры», наполненные свойствами (называемыми собственными свойствами). Каждый объект содержит ссылку на свой объект-прототип.
При попытке получить доступ к какому-либо свойству объекта, свойство вначале ищется в самом объекте, затем в прототипе объекта, после чего в прототипе прототипа, и так далее. Поиск ведётся до тех пор, пока не найдено свойство с совпадающим именем или не достигнут конец цепочки прототипов.

При добавлении к объекту нового свойства, создаётся новое собственное свойство (own property). Единственным исключением из этого правила являются наследуемые свойства, имеющие .

JavaScript не имеет «методов» в смысле, принятом в классической модели ООП. В JavaScript любая функция может быть добавлена к объекту в виде его свойства. Унаследованная функция ведёт себя точно так же, как любое другое свойство объекта, в том числе и в плане «затенения свойств» (property shadowing), как показано в примере выше (в данном конкретном случае это форма переопределения метода — method overriding).

В области видимости унаследованной функции ссылка указывает на наследующий объект (на наследника), а не на прототип, в котором данная функция является собственным свойством.

Определение функции-конструктора Teacher()

Первое, что нам нужно сделать, это создать конструктор — добавьте ниже следующий код:

Это похоже на конструктор Person во многих отношениях, но здесь есть что-то странное, что мы не видели раньше — функцию . Эта функция в основном позволяет вам вызывать функцию, определённую где-то в другом месте, но в текущем контексте. Первый параметр указывает значение , которое вы хотите использовать при выполнении функции, а остальные параметры — те, которые должны быть переданы функции при её вызове.

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

Последняя строка внутри конструктора просто определяет новое свойство , которое будут иметь учителя, и которого нет у Person().

В качестве примечания мы могли бы просто сделать это:

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

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

Вы можете наследовать свойства и , выполнив это (как и другие шаги, описанные ниже, конечно):

Обратите внимание, что мы указали только внутри  — никаких других параметров не требуется, поскольку мы не наследуем никаких свойств родителя, которые задаются через параметры

Закрытое наследование

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

Обратите внимание, что это не влияет на способ доступа производного класса к членам, унаследованным от его родителя! Это влияет только на код, пытающийся получить доступ к этим членам через производный класс. Подведем итоги в виде таблицы:

Подведем итоги в виде таблицы:

Спецификатор доступа в базовом классе Спецификатор доступа при закрытом наследовании
не доступен

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

На практике закрытое наследование используется редко.

Наследование таблицы классов (также известное как наследование таблиц по типам):

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

Это решение решает проблемы, выявленные в двух других конструкциях:

  • Обязательные атрибуты могут быть применены с помощью .

  • Добавление нового подтипа требует добавления новой таблицы вместо добавления столбцов к существующей.

  • Отсутствие риска того, что для определенного подтипа будет установлен несоответствующий атрибут.

  • Нет необходимости в атрибут.

  • Теперь общие атрибуты больше не смешиваются с атрибутами конкретных подтипов.

  • Наконец-то мы можем оставаться СУХИМИ. При создании таблиц нет необходимости повторять общие атрибуты для каждой таблицы подтипа.

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

  • Теперь поиск всех политик независимо от подтипа стал очень простым: Нет необходимо — просто .

Я считаю подход таблицы классов наиболее подходящим в большинстве ситуаций.

Названия этих трех моделей взяты из книги Мартина Фаулера «Шаблоны архитектуры корпоративных приложений».

  • 104 Я тоже использую этот дизайн, но вы не упоминаете о недостатках. В частности: 1) вы говорите, что вам не нужен тип; true, но вы не можете определить фактический тип строки, если не посмотрите на все таблицы подтипов, чтобы найти совпадение. 2) Трудно поддерживать синхронизацию главной таблицы и таблиц подтипов (можно, например, удалить строку в таблице подтипов, а не в главной таблице). 3) У вас может быть более одного подтипа для каждой основной строки. Я использую триггеры, чтобы обойти 1, но 2 и 3 — очень сложные проблемы. На самом деле 3 не проблема, если вы моделируете композицию, но для строгого наследования.
  • 20 +1 за комментарий @Tibo, это серьезная проблема. Наследование таблицы классов фактически дает ненормализованную схему. В отличие от наследования конкретной таблицы, и я не согласен с аргументом, что наследование конкретной таблицы препятствует DRY. SQL мешает DRY, потому что у него нет средств метапрограммирования. Решение состоит в том, чтобы использовать Database Toolkit (или написать свой собственный) для выполнения тяжелой работы, вместо того, чтобы напрямую писать SQL (помните, что на самом деле это только язык интерфейса БД). В конце концов, вы также не пишете свое корпоративное приложение на ассемблере.
  • 18 @Tibo, насчет пункта 3, вы можете использовать подход, описанный здесь: sqlteam.com/article/…, проверьте Моделирование взаимно-однозначных ограничений раздел.
  • 4 @DanielVassallo Во-первых, спасибо за потрясающий ответ, я сомневаюсь, что у человека есть policyId, как узнать, его policy_motor или policy_property? Один из способов — найти policyId во всех вложенных таблицах, но я думаю, это плохой способ, не так ли? Каким должен быть правильный подход?
  • 14 Мне очень нравится твой третий вариант. Однако я не понимаю, как будет работать SELECT. Если вы SELECT * FROM policy, вы получите обратно идентификаторы политик, но вы все равно не узнаете, к какой таблице подтипов принадлежит политика. Вам все равно придется выполнять JOIN со всеми подтипами, чтобы получить все подробности политики?

Третий вариант — создать таблицу «Политика», а затем таблицу «SectionsMain», в которой хранятся все поля, общие для всех типов разделов. Затем создайте другие таблицы для каждого типа раздела, содержащие только поля, которые не являются общими.

Решение о том, что лучше, в основном зависит от того, сколько полей у вас есть и как вы хотите писать свой SQL. Все они будут работать. Если у вас всего несколько полей, я бы, вероятно, выбрал №1. С «большим количеством» полей я бы склонился к №2 или №3.

  • +1: 3-й вариант наиболее близок к модели наследования и наиболее нормализован IMO
  • Ваш вариант №3 — это именно то, что я имел в виду под вариантом №2. Есть много полей, и у некоторых разделов тоже есть дочерние сущности.

Имея предоставленную информацию, я бы смоделировал базу данных следующим образом:

Попробуйте пример

Теперь, когда вы ввели весь код, попробуйте создать экземпляр объекта из , поставив ниже вашего JavaScript-кода (или что-то похожее по вашему выбору):

Теперь сохраните, обновите, и попробуйте получить доступ к свойствам и методам вашего нового объекта , например:

Все должно работать нормально. Запросы в строках 1, 2, 3 и 6 унаследованные от общего конструктора (класса). Запрос в строке 4 обращается к , доступному только для более специализированного конструктора (класса) . Запрос в строке 5 получил бы доступ к методу , унаследованному от , но  имеет свой собственный метод  с тем же именем, поэтому запрос обращается к этому методу.

Примечание. Если вам не удаётся заставить это работать, сравните свой код с нашей готовой версией (см. также рабочее демо).

Методика, которую мы здесь рассмотрели, — это не единственный способ создания наследующих классов в JavaScript, но он работает нормально и это даёт вам представление о том, как реализовать наследование в JavaScript.

Вам также может быть интересно узнать некоторые из новых функций ECMAScript, которые позволяют нам делать наследование более чисто в JavaScript (см. Classes). Мы не рассматривали их здесь, поскольку они пока не поддерживаются очень широко в браузерах. Все остальные конструкторы кода, которые мы обсуждали в этом наборе статей, поддерживаются ещё в IE9 или ранее и есть способы добиться более ранней поддержки, чем это.

Обычный способ — использовать библиотеку JavaScript — большинство популярных опций имеют простой набор функций, доступных для выполнения наследования более легко и быстро. , например, предоставляет класс, расширяет и т.д.

Понимание наследования

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

Цвет шрифта применён к прямому потомку, но также и к непрямому потомку — к прямому потомку  и к элементам внутри первого вложенного списка. Далее мы добавили класс  ко второму вложенному списку и применили к нему другой цвет шрифта. Теперь это свойство наследуется всеми его потомками.

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

Какие свойства наследуются по умолчанию, а какие нет, чаще всего определяется здравым смыслом.

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

Устанавливает значение свойства, применённого к элементу, таким же, как у его родительского элемента. Фактически, это «включает наследование».
Устанавливает значение свойства, применённого к выбранному элементу, равным initial value этого свойства (в соответствии с настройками браузера по умолчанию. Если в таблице стилей браузера отсутствует значение этого свойства, оно наследуется естественным образом.)
(en-US)
Возвращает свойству его естественное значение, что означает, что если свойство наследуется естественным образом, оно действует как , иначе оно действует как .

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

Примечание: Смотрите в для более подробной информации о каждом из них, и о том, как они работают.

Можно посмотреть список ссылок и изучить, как работают универсальные значения. Пример, следующий ниже, позволяет вам поиграть с CSS и увидеть, что происходит, когда вы вносите изменения. Подобные эксперименты с кодом — лучший способ освоить HTML и CSS.

Например:

  1. Второй элемент списка имеет класс . Таким образом, цвет для следующего вложенного элемента устанавливается по наследству. Как изменится цвет, если это правило будет удалено?
  2. Понятно ли, почему третий и четвёртый элементы имеют именно такой цвет? Если нет, перечитайте описание значений, представленное выше.
  3. Какая из ссылок изменит цвет, если вы зададите новый цвет для элемента  — например: ?

Стенографическое свойство CSS можно использовать для того, чтобы присвоить одно из значений наследования к (почти) всем свойствам одновременно. Это одно из четырёх значений (, , , или ). Это удобный способ для отмены изменений, внесённых в стили, для того, чтобы вы могли вернуться к стартовой точке перед внесением новых изменений.

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

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

СЛУЧАЙ SQL

Если вы не используете Oracle или SQL Server, вы все равно можете транспонировать строки в столбцы, используя выражение CASE и предложение GROUP BY:

SELECT 
    p.service_name AS "serviceName", 
    p.component_name AS "componentName", 
    MAX(
        CASE WHEN property_name = 'databaseName' 
        THEN property_value END
    ) AS "databaseName", 
    MAX(
        CASE WHEN property_name = 'url' 
        THEN property_value END) 
    AS "url", 
    MAX(
        CASE WHEN property_name = 'serverName' 
        THEN property_value END
    ) AS "serverName", 
    MAX(
        CASE WHEN property_name = 'username' 
        THEN property_value END
    ) AS "userName", 
    MAX(
        CASE WHEN property_name = 'password' 
        THEN property_value END
    ) AS "password" 
FROM Property p 
WHERE 
   p.component_name = :name 
GROUP BY 
    p.service_name, 
    p.component_name

Этот запрос возвращает следующий результат:

dataSources = {java.util.ArrayList@4992}  size = 2
 0 = {com.vladmihalcea.book.hpjp.hibernate.query.pivot.DataSourceConfiguration@4993} 
  serviceName = "Apollo"
  componentName = "dataSource"
  databaseName = "high_performance_java_persistence"
  url = null
  serverName = "192.168.0.5"
  userName = "postgres"
  password = "admin"
 1 = {com.vladmihalcea.book.hpjp.hibernate.query.pivot.DataSourceConfiguration@5177} 
  serviceName = "Artemis"
  componentName = "dataSource"
  databaseName = "high_performance_java_persistence"
  url = "jdbc:oracle:thin:@192.169.0.6:1521/hpjp"
  serverName = null
  userName = "oracle"
  password = "admin"
Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: