Связи таблиц sql

Как определить связи между таблицами

При создании связи между таблицами связанные поля не должны иметь одни и те же имена. Однако связанные поля должны иметь один и тот же тип данных, если только поле первичного ключа не является полем AutoNumber. Вы можете сопоставить поле AutoNumber с полем Number, только если свойство FieldSize обоих совпадающих полей совпадает. Например, можно сопоставить поле AutoNumber и поле Number, если свойство theFieldSizeproperty обоих полей имеет значение Long Integer. Даже если оба совпадающих поля являются числовыми полями, они должны иметь параметр sameFieldSizeproperty.

Как определить связи «один ко многим» или «один к одному»

Чтобы создать связь «один ко многим» или «один к одному», выполните следующие действия.

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

  2. В Access 2002 и Access 2003 выполните следующие действия.

    1. Нажмите F11, чтобы переключиться в окно базы данных.
    2. В меню Инструменты выберите Связи.

    В Access 2007, Access 2010 или Access 2013 нажмите Связи в группе Показать/Скрыть на вкладке Инструменты базы данных.

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

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

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

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

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

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

  7. Нажмите кнопку Создать, чтобы создать связь.

  8. Повторите шаги с 4 по 7 для каждой пары таблиц, которые вы хотите связать.

    При закрытии диалогового окна Изменение связей Access спрашивает, хотите ли вы сохранить макет. Сохраняете ли вы макет или не сохраняете макет, созданные вами связи сохраняются в базе данных.

    Примечание

    Можно создавать связи не только в таблицах, но и в запросах. Однако целостность данных связывания не обеспечивается с помощью запросов.

Как определить связь «многие ко многим»

Чтобы создать связь «многие ко многим», выполните следующие действия.

  1. Создайте две таблицы, которые будут иметь связь «многие ко многим».

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

  3. В связующей таблице установите первичный ключ, чтобы включить основные ключевые поля из двух других таблиц. Например, в связующей таблице «TitleAuthors» первичный ключ будет состоять из полей OrderID и ProductID.

    Примечание

    Чтобы создать первичный ключ, выполните следующие действия:

    1. Откройте таблицу в Конструкторе.

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

    3. В Access 2002 или в Access 2003 нажмите на Первичный ключ на панели инструментов.

      В Access 2007 нажмите на Первичный ключ в группе Инструменты на вкладке Дизайн.

      Примечание

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

  4. Определите связь один-ко-многим между каждой основной и связующей таблицами.

Связь один ко многим

Последнее обновление: 17.12.2015

Связь один-ко-многим реализуется, если одна модель хранит ссылку на один объект другой модели, а вторая модель может ссылаться на коллекцию объектов первой модели.
Например, в одной команде играет несколько игроков:

public class Player
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Position { get; set; }
    public int Age { get; set; }

    public int? TeamId { get; set; }
    public Team Team { get; set; }
}
public class Team
{
    public int Id { get; set; }
    public string Name { get; set; } // название команды

    public ICollection<Player> Players { get; set; }
	public Team()
    {
        Players = new List<Player>();
    }
}
public class SoccerContext : DbContext
{
    public SoccerContext() : base("SoccerContext")
    {}

    public DbSet<Player> Players { get; set; }
    public DbSet<Team> Teams { get; set; }
}

Добавление и вывод:

using(SoccerContext db = new SoccerContext())
{
    // создание и добавление моделей
    Team t1 = new Team { Name = "Барселона" };
    Team t2 = new Team { Name = "Реал Мадрид" };
    db.Teams.Add(t1);
    db.Teams.Add(t2);
    db.SaveChanges();
    Player pl1 = new Player {Name = "Роналду", Age = 31, Position = "Нападающий", Team=t2 };
    Player pl2 = new Player { Name = "Месси", Age = 28, Position = "Нападающий", Team=t1 };
    Player pl3 = new Player { Name = "Хави", Age = 34, Position = "Полузащитник", Team=t1 };
    db.Players.AddRange(new List<Player>{pl1, pl2,pl3});
	db.SaveChanges();
                
	// вывод 
    foreach(Player pl in db.Players.Include(p=>p.Team))
        Console.WriteLine("{0} - {1}", pl.Name, pl.Team!=null?pl.Team.Name:"");
    Console.WriteLine();
    foreach(Team t in db.Teams.Include(t=>t.Players))
    {
        Console.WriteLine("Команда: {0}", t.Name);
        foreach(Player pl in t.Players)
        {
            Console.WriteLine("{0} - {1}", pl.Name, pl.Position);
        }
        Console.WriteLine();
    }
}

Результат вывода:

Редактирование:

//редактирование
t2.Name = "Реал М."; // изменим название
db.Entry(t2).State = EntityState.Modified;
// переведем игрока из одной команды в другую
pl3.Team = t2;
db.Entry(pl3).State = EntityState.Modified;
db.SaveChanges();

При удалении объектов, связанных отношением «один-ко-многим» нам надо учитывать то, что по умолчанию даже если внешний ключ допускает значение null
(как в данном случае свойство TeamId в классе Player), мы не сможем просто так удалить одну модель, если она имеет ссылки на другую модель.
Например, удаление команды в данном случае выльется в ошибку, если какой-то объект Player имеет ссылку на эту команду. Что делать в этом случае?
В этом случае нам надо установить для внешнего ключа TeamId в таблице игроков ограничение . Данное ограничение позволит
при удалении связанного объекта устанавливать для внешнего ключа значение null.

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

 db.Database.ExecuteSqlCommand("ALTER TABLE dbo.Players ADD CONSTRAINT Players_Teams FOREIGN KEY (TeamId) REFERENCES dbo.Teams (Id) ON DELETE SET NULL");
 

Здесь добавляется ограничение «Players_Teams» в таблицу игроков, которая называется, как правило, dbo.Players или просто Players. Это ограничение указывает, что для
внешнего ключа TeamId из таблицы Players, который связан со столбцом Id из таблицы dbo.Teams, устанавливается правило «ON DELETE SET NULL», то есть установка null по удалению.

И после этого мы можем выполнить удаление:

//удаление игрока
Player pl_toDelete = db.Players.First(p => p.Name == "Роналду");
db.Players.Remove(pl_toDelete);
// удаление команды     
Team t_toDelete = db.Teams.First();
db.Teams.Remove(t_toDelete);
db.SaveChanges();

При удалении команды свойство Team у объектов Player получает значение null.

НазадВперед

Microsoft Access

Офисный программный продукт от «Майкрософт» известен на рынке ПО уже довольно продолжительное время. Он поставляется вместе с текстовым редактором Worfd, табличным процессором Excel и прочими, входящими в линейку «офиса». Можно Access (читается как «аксес», дословный перевод — «доступ») приобрести и отдельно от его «коллег». Рекомендуется купить, разумеется, лицензионный софт, но ни для кого не секрет, сколько пиратских репаков можно найти на просторах Сети, в виде обычных файлов или раздач торрентов. «Майкрософт Аксес» доступен даже в портативной сборке. Она, не требующая инсталляции и особых навыков работы с ПК, лучше всего подходит для выбора, если ПО не будет использоваться продолжительно и часто.

Из контекста ясно, что «Майкрософт Аксес» — это система управления базами данных. Причем одна из популярнейших. Она является реляционной, что значит, она основана на логической модели данных, которая в ходе своей работы обращается к теории множеств и логике первого порядка. Связь многие-ко-многим в Access (примеры будут даны в ходе объяснения) реализуется очень и очень просто. Рассмотрим ее.

Создание и изменение отношений 1:N между сущностями

Откройте обозреватель решений.

В разделе Компоненты раскройте узел Сущности, затем раскройте сущность, с которой требуется работать.

Выберите Отношения 1:N.

Чтобы изменить отношение или просмотреть сведения для отношения, выберите отношение и нажмите на панели инструментов «Действия» кнопку Другие действия, затем выберите Изменить.
— ИЛИ —
Чтобы добавить новое отношение, выберите Создать отношение «один ко многим».

Важно!
Если кнопка Создать отношение «один ко многим» не отображается на панели инструментов «Действия», то создать отношение 1:N для этой сущности невозможно.

Для нового отношения в разделе Определение отношения выберите в списке Связанная сущность сущность для связывания.

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

Выберите, будет ли это поле доступно для поиска или нет.

В разделе Поле поиска укажите значение для поля в поле Отображаемое имя.

Важно!
При указании значения Отображаемое имя задается значение по умолчанию в поле Имя

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

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

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

В разделе Поведение отношений выберите в списке Тип отношений один из следующих вариантов.

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

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

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

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

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

Дополнительные сведения:

  1. Выберите Сохранить и закрыть, чтобы закрыть форму Отношение.

  2. Выполнив настройки, опубликуйте их:

    • Чтобы опубликовать настройки только для компонента, изменяемого в данный момент, на панели инструментов «Действия» выберите Опубликовать.

    • Чтобы опубликовать настройки для всех неопубликованных компонентов одновременно, на панели навигации или в области переходов выберите Сущности, затем на панели инструментов «Действия» выберите Опубликовать все настройки.

Примечание

  • Настраиваемая сущность не может быть основной в каскадном отношении со связанной системной сущностью. Это означает, что между основной настраиваемой сущностью и связанной системной сущностью не может быть отношений с каким-либо из действий, установленным в «Передавать всем», «Передавать активным» или «Передавать владельцу».
  • У новых отношений действие не может иметь значение Передавать всем, Передавать активным или Передавать владельцу, если связанная сущность в этом отношении уже является связанной сущностью в любом другом отношении, действие которого имеет значение Передавать всем, Передавать активным или Передавать владельцу. Это позволяет избежать создания отношений с несколькими родительскими сущностями.
  • После каждого изменения элементов пользовательского интерфейса или внедрения скриптов формы для сущности необходима публикация изменений. Все изменения в схеме данных приложения, таких как настраиваемые сущности, связи или поля, применяются сразу.
  • Если отношение является частью управляемого решения, разработчик решения может ограничить настройку отношения пользователями.
  • Установка решения или публикация настроек может помешать нормальной работе системы. Рекомендуется запланировать импорт решения в оптимальный для пользователей период.

Mapping отношений Многие к Одному.

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

С точки зрения сущности «Продукт» это отношение «многие к одному». С точки зрения сущности Category это отношение один ко многим.

Чтобы отобразить это, сначала создайте свойство категории в классе Product с аннотацией ManyToOne. Вы можете сделать это вручную или с помощью команды make:entity, которая задаст вам несколько вопросов о ваших отношениях. Если вы не уверены в ответе, не волнуйтесь! Вы всегда можете изменить настройки позже:

 php bin/console make:entity

Class name of the entity to create or update (e.g. BraveChef):
> Product

 to stop adding fields):
> category

Field type (enter ? to see all types) :
> relation

What class should this entity be related to?:
> Category

Relation type? :
> ManyToOne

Is the Product.category property allowed to be null (nullable)? (yes/no) :
> no

Do you want to add a new property to Category so that you can access/update
getProducts()? (yes/no) :
> yes

New field name inside Category :
> products

Do you want to automatically delete orphaned App\Entity\Product objects
(orphanRemoval)? (yes/no) :
> no

 to stop adding fields):
>
(press enter again to finish)

Это внесло изменения в две сущности. Во-первых, он добавил новое свойство category в сущность Product (и методы getter & setter):

// src/Entity/Product.php

// ...
class Product
{
    // ...

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products")
     */
    private $category;

    public function getCategory(): ?Category
    {
        return $this->category;
    }

    public function setCategory(?Category $category): self
    {
        $this->category = $category;

        return $this;
    }
}

Это сопоставление ManyToOne требуется. Он говорит Doctrine использовать столбец category_id в таблице продуктов, чтобы связать каждую запись в этой таблице с записью в таблице категорий.

Далее, поскольку один объект Category будет относиться ко многим объектам Product, команда make: entity также добавила свойство products в класс Category, который будет содержать эти объекты:

// src/Entity/Category.php

// ...
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

class Category
{
    // ...

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="category")
     */
    private $products;

    public function __construct()
    {
        $this->products = new ArrayCollection();
    }

    /**
     * @return Collection|Product[]
     */
    public function getProducts(): Collection
    {
        return $this->products;
    }

    // addProduct() and removeProduct() were also added
}

Отображение ManyToOne, показанное ранее, является обязательным, но это OneToMany не является обязательным: добавляйте его только в том случае, если вы хотите иметь доступ к продуктам, которые относятся к категории (это один из вопросов, которые задает make: entity вас спрашивает). В этом примере будет полезно иметь возможность вызывать $ category-> getProducts (). Если вы не хотите этого, то вам также не нужно конфигурация inversedBy или mappedBy.

Один к одному (one-to-one)

Связь один к одному это когда одной записи в таблице отвечает только одна запись из другой таблицы. Чтобы продемонстрировать связь один к одному возьмем таблицу supplier:

и вынесем колонку full_address в отдельную таблицу. Таким образом в таблице supplier будет ссылка на таблицу address, в которой будут такие поля: address_id, coutry, city, street.

Не теряя времени сделаем нужные изменения.

alter table supplier modify column full_address int;

Так как поле full_address будет ссылкой на таблицу address сделаем его тип целочисленным.

Далее создадим саму таблицу address.

create table address(address_id int auto_increment primary key, country text, city text, street text);

Теперь укажем, что поле full_address будет внешним ключом:

alter table supplier add foreign key (full_address) references address(address_id);

Связь один к одному означает, что в таблице supplier будет уникальный идентификатор записи с таблицы address. Поэтому, нужно сделать поле full_address уникальным:

alter table supplier add foreign key (full_address) references address(address_id);

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

Добавление необходимых таблиц к представлению источника данных

Откройте конструктор представлений источника данных для представления источников данных Adventure Works DW 2012 .

Щелкните правой кнопкой мыши панель Организатор диаграмм , выберите команду Создать диаграмму и укажите Причина заказа через Интернет в качестве имени созданной диаграммы.

Перетащите таблицу InternetSales с панели Таблицы на панель Диаграмма .

Щелкните правой кнопкой мыши панель Диаграмма и выберите команду Добавить или удалить таблицы.

В диалоговом окне Добавление или удаление таблиц добавьте в список Включенные объекты таблицы DimSalesReason и FactInternetSalesReason , а затем нажмите кнопку ОК.
Обратите внимание, что связи «первичный-внешний ключ» между задействованными таблицами устанавливаются автоматически, поскольку эти связи определяются в базовой реляционной базе данных. Если эти связи не определены в базовой реляционной базе данных, их следует определить в представлении источника данных.

В меню Формат выберите команду Автоматический макет и щелкните значок Диаграмма.

В окне свойств измените свойство FriendlyName таблицы DimSalesReason на SalesReason, затем измените свойство FriendlyName таблицы FactInternetSalesReason на InternetSalesReason.

На панели Таблицы разверните узел InternetSalesReason (dbo.FactInternetSalesReason), щелкните столбец SalesOrderNumber и просмотрите в окне свойств свойство DataType для этого столбца данных.
Обратите внимание, что в качестве типа данных для столбца SalesOrderNumber указан тип данных string.

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

На панели Таблицы щелкните правой кнопкой мыши таблицу InternetSalesReason (dbo.FactInternetSalesReason) и выберите пункт Просмотр данных.
Обратите внимание, что для каждого номера строки каждого заказа значение ключа указывает причину покупки данной позиции линии, как показано на следующем рисунке.

Связь один-к-одному

Последнее обновление: 17.05.2019

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

Для создания подобной связи между моделями применяется метод hasOne(). Например, определим модели тренера и команды:

const Sequelize = require("sequelize");

const sequelize = new Sequelize("game", "root", "123456", {
    dialect: "mysql",
    host: "localhost",
    define: {
      timestamps: false
    }
});
const Coach = sequelize.define("coach", {
  id: {
    type: Sequelize.INTEGER,
    autoIncrement: true,
    primaryKey: true,
    allowNull: false
  },
  name: {
    type: Sequelize.STRING,
    allowNull: false
  }
});
const Team = sequelize.define("team", {
  id: {
    type: Sequelize.INTEGER,
    autoIncrement: true,
    primaryKey: true,
    allowNull: false
  },
  name: {
    type: Sequelize.STRING,
    allowNull: false
  }
});

Coach.hasOne(Team, { onDelete: "cascade"});

sequelize.sync({force:true}).then(()=>{

  console.log("Tables have been created");
}).catch(err=>console.log(err));

В данном случае модель тренера (Coach) условно считается главной, а модель команды (Team) зависимой (но в данном случае деление на главную и зависимую модель
достаточно условно). Поэтому метод вызывается у модели Coach, и в качестве первого параметра передается модель Team. Хотя в данном случае не имеет значения, какая именно модель является главной или зависимой.
Второй параметр метода задает конфигурацию связи, в частности, каскадное удаление.

В итоге при выполнении данного когда в MySQL будут созданы следующие таблицы:

CREATE TABLE `coaches` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf-8 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE `teams` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `coachId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `coachId` (`coachId`),
  CONSTRAINT `teams_ibfk_1` FOREIGN KEY (`coachId`) REFERENCES `coaches` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf-8 COLLATE=utf8mb4_0900_ai_ci;

Как мы видим, в таблице teams создается дополнительный столбец coachId, через который данная таблица будет связана с таблицей coaches.

Добавление и получение связанных данных

Для установки связанных данных применяется метод setНАЗВАНИЕ_МОДЕЛИ(). Например, добавим тренера и его команду:

// добавляем тренера
Coach.create({ name: "Tom Smith"})
.then(coach=>{
	// Добавляем команду
	Team.create({name:"Real Madrid"}).then(team=>{
		// устанавливаем для тренера команду
		coach.setTeam(team).catch(err=>console.log(err));
	});
}).catch(err=>console.log(err));

По факту метод будет вызывать SQL-команду UPDATE. То есть к моменту вызова данного метода связываемые сущности уже должны быть в
базе данных.

Для получения связанных данных применяется метод getНАЗВАНИЕ_МОДЕЛИ(). Например, получим тренера и его команду:

// получаем тренера с id=1
Coach.findByPk(1).then(coach=>{
	if(!coach) return console.log("Coach not found");
    coach.getTeam().then(team=>{
        console.log(coach.name, "-", team.name);
    });
});

В данном случае на консоли мы получим:

Tom Smith - Real Madrid

Получение всех тренеров с включением связанных данных:

Coach.findAll({
    attributes: , // включаем столбец name из таблицы coaches
    include:   // включаем столбец name из таблицы teams
    }]
  }).then(coaches => {
      for(coach of coaches){
        console.log(coach.name, "-", coach.team.name);
      }
});

НазадВперед

Значения ON DELETE и ON UPDATE

CASCADE — Каскадное удаление и редактирование. Эта настройка означает, что при удалении каталога, все товары из него тоже удалятся. При редактировании, если мы изменим id каталога, у товаров автоматически изменится поле «catalog_id».

RESTRICT — При этой настройке, если мы попытаемся удалить каталог, в котором есть товары, или изменить его id, база данных выдаст нам ошибку и удаление не состоится.

SET NULL — Из названия видно, что если исчезнет(удалится или изменится) каталог с таким id, то у товаров в поле «catalog_id» установится значение NULL

С этой настройкой нужно вести себя осторожно, потому что по умолчанию индексы «NOT NULL»

NO ACTION — Игнорируем удаление и редактирование каталога, и пусть в поле «catalog_id» будет несуществующий идентификатор, просто игнорируем это.

Отношение один ко многим

Последнее обновление: 17.11.2020

Связь один-ко-многим (one-to-many) представляет ситуацию, когда одна модель хранит ссылку на один объект другой модели, а вторая
модель может ссылаться на коллекцию объектов первой модели. Например, в одной компании может работать несколько сотрудников, а каждый сотрудник в
свою очередь может официально работать только в одной компании:

public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<User> Users { get; set; } = new List<User>(); // сотрудники компании
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int CompanyId { get; set; }
    public Company Company { get; set; }  // компания пользователя
}

public class ApplicationContext : DbContext
{
    public DbSet<Company> Companies { get; set; }
    public DbSet<User> Users { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=relationsdb;Trusted_Connection=True;");
    }
}

Добавление данных:

using (ApplicationContext db = new ApplicationContext())
{
	// пересоздадим базу данных
	db.Database.EnsureDeleted();
	db.Database.EnsureCreated();
	
    // создание и добавление моделей
    Company microsoft = new Company { Name = "Microsoft" };
    Company google = new Company { Name = "Google" };
    db.Companies.AddRange(microsoft, google);

    User tom = new User { Name = "Tom", Company = microsoft };
    User bob = new User { Name = "Bob", Company = microsoft };
    User alice = new User { Name = "Alice", Company = google };
    db.Users.AddRange(tom, bob, alice);
    db.SaveChanges();
}

Получение данных:

using (ApplicationContext db = new ApplicationContext())
{
    // вывод пользователей
    var users = db.Users.Include(u => u.Company).ToList();
    foreach (User user in users)
        Console.WriteLine($"{user.Name} - {user.Company?.Name}");

    // вывод компаний
	var companies = db.Companies.Include(c => c.Users).ToList();
    foreach (Company comp in companies)
    {
        Console.WriteLine($"\n Компания: {comp.Name}");
        foreach (User user in comp.Users)
        {
            Console.WriteLine($"{user.Name}");
        }
    }
}

Редактирование:

using (ApplicationContext db = new ApplicationContext())
{
	// изменение имени пользователя
    User user1 = db.Users.FirstOrDefault(p => p.Name == "Tom");
    if (user1!=null)
    {
        user1.Name = "Tomek";
        db.SaveChanges();
    }
	// изменение названия компании
    Company comp = db.Companies.FirstOrDefault(p => p.Name == "Google");
    if (comp != null)
    {
        comp.Name = "Alphabet";
        db.SaveChanges();
    }
                
    // смена компании сотрудника
    User user2 = db.Users.FirstOrDefault(p => p.Name == "Bob");
    if (user2 != null && comp!=null)
    {
        user2.Company = comp;
        db.SaveChanges();
    }
}

Удаление:

using (ApplicationContext db = new ApplicationContext())
{
    User user1 = db.Users.FirstOrDefault(p => p.Name == "Bob");
    if (user1!=null)
    {
        db.Users.Remove(user1);
        db.SaveChanges();
    }

    Company comp = db.Companies.FirstOrDefault();
    if (comp != null)
    {
        db.Companies.Remove(comp);
        db.SaveChanges();
    }
}

Следует учитывать, что если зависимая сущность (в данном случае User) требует обязательного наличия главной сущности (в данном случае Company),
то на уровне базы данных при удалении главной сущности с помощью каскадного удаления будут удалены и связанные с ней зависимые сущности. Так,
в данном случае для объекта User установлено обязательное наличие объекта Company:

public int CompanyId { get; set; }
public Company Company { get; set; }  // компания пользователя

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

НазадВперед

Ассоциация ManyToOne / OneToMany.

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

Начните с создания Category с полем name:

 php bin/console make:entity Category

 New property name (press <return> to stop adding fields):
> name

Field type (enter ? to see all types) :
> string

Field length :
> 255

Can this field be null in the database (nullable) (yes/no) :
> no

 New property name (press <return> to stop adding fields):
>
(press enter again to finish)

Это сгенерирует ваш новый класс сущности:

// src/Entity/Category.php
// ...

class Category
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     */
    private $name;

    // ... getters and setters
}
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector