Original
https://msdn.microsoft.com/ru-ru/data/jj713564.aspx
https://msdn.microsoft.com/ru-ru/data/jj713564.aspx
Связи и свойства навигации
В этом разделе приведены общие сведения о том, как платформа Entity Framework управляет связями между сущностями. Раздел также содержит ряд рекомендаций по сопоставлению и управлению связями.
Связи, свойства навигации и внешние ключи
В реляционных базах данных связи (или ассоциации) между таблицами определяются с помощью внешних ключей. Внешний ключ (ВН) — это столбец или сочетание столбцов, которое применяется для принудительного установления связи между данными в двух таблицах. Существует три типа связей: «один к одному», «один ко многим» и «многие ко многим». В связи «один ко многим» внешний ключ определяется для таблицы, на которую указывает конец связи «многие». Для связи «многие ко многим» нужно определить третью таблицу (так называемую соединяющую таблицу), первичный ключ в которой состоит из внешних ключей из обеих связанных таблиц. В связи «один к одному» первичный ключ также является внешним ключом, при этом ни в одной из таблиц нет отдельного столбца внешнего ключа.
На следующем образе показаны две таблицы, которые участвуют в связи «один ко многим». Таблица Course является зависимой, так как содержит столбец DepartmentID, который связывает ее с таблицей Department.
Сущность в Entity Framework может быть связана с другими сущностями посредством ассоциации (связи). Каждая связь содержит два конечных элемента, которые описывают тип сущности и кратность типа («один», «нуль или один» или «многие») для обеих сущностей в связи. Отношение может управляться справочным ограничением, описывающим, какой из конечных элементов отношения относится к основной роли, а какой к зависимой роли.
Свойства навигации предоставляют способ перемещения по ассоциации между типами сущностей. Каждый объект может обладать свойством навигации для каждого отношения, в котором участвует. Свойства навигации позволяют передвигаться по связям и управлять ими в обоих направлениях, а также возвращают ссылочный объект (если кратность равна одному либо нулю или одному) или коллекцию (если кратность больше одного). Можно также выбрать одностороннюю навигацию. В этом случае необходимо определить свойство навигации только для одного из типов, участвующих в связи, а не для обоих.
Рекомендуется включать в модель свойства, сопоставленные с внешними ключами в базе данных. Включение свойств внешних ключей позволяет создавать или изменять отношение, изменяя значение внешнего ключа для зависимого объекта. Сопоставление такого типа называется сопоставлением на основе внешнего ключа. Использование внешних ключей особенно важно при работе с многоуровневыми приложениями. Обратите внимание, что при работе со связью «1 к 1» или «1 к 0–1» отсутствует отдельный столбец внешних ключей, свойство первичного ключа выступает в качестве внешнего ключа и всегда включено в модель.
Если столбцы внешних ключей не включены в модель, информация об ассоциации управляется как независимый объект. Связи отслеживаются посредством объектных ссылок вместо свойств внешнего ключа. Такой тип ассоциации называется независимым сопоставлением. Самым распространенным способом изменения независимого сопоставления является изменение свойств навигации, которые создаются для каждой сущности, участвующей в ассоциации.
В модели можно использовать один или оба типа ассоциаций. Однако, если имеется простая связь «многие ко многим», установленная посредством таблицы соединения, содержащей только внешние ключи, для управления такой связью платформа Entity Framework будет использовать независимое сопоставление.
На следующем образе показана концептуальная модель, созданная с помощью конструктора Entity Framework. Модель содержит две сущности, участвующие в связи «один ко многим». Обе сущности имеют свойства навигации. Course — зависимая сущность с определенным внешним ключомDepartmentID.
На образе ниже показана та же модель, созданная с помощью Code First.
Настройка и сопоставление связей
Далее рассматривается доступ к данным и управление данными с помощью связей. Дополнительные сведения об установлении связей в модели см. на следующих страницах.
- Сведения о настройке связей в Code First см. в разделах Заметки к данным и Fluent API — связи.
- Сведения о настройке связей с помощью конструктора Entity Framework см. в разделе Связи в конструкторе Entity Framework.
Создание и изменение отношений
При изменении связи для сопоставления на основе внешнего ключа состояние зависимого объекта меняется с EntityState.Unchanged на EntityState.Modified. Изменение связи не обновляет состояние зависимого объекта в независимой связи.
В следующем примере рассматривается использование свойства внешнего ключа и свойства навигации для установления связи между объектами. С помощью сопоставлений на основе внешнего ключа можно изменять и создавать связи. Для независимых сопоставлений нельзя использовать свойство внешнего ключа.
- С помощью присваивания нового значения свойству внешнего ключа, как показано в следующем примере.
course.DepartmentID = newCourse.DepartmentID;
- Следующий код удаляет связь путем присвоения внешнему ключу значения NULL. Обратите внимание, что свойство внешнего ключа должно допускать значение NULL.
course.DepartmentID = null;
Примечание. Если ссылка находится в добавленном состоянии (в данном примере объект course), свойство навигации ссылки не будет синхронизировано со значениями ключа нового объекта, пока не будет вызван метод SaveChanges. Синхронизация не выполняется, поскольку контекст объекта не содержит постоянных ключей для добавленных объектов, пока они не будут сохранены. Если необходимо, чтобы новые объекты были полностью синхронизированы сразу после установления связи, используйте один из следующих методов.
- С помощью присваивания нового объекта свойству навигации. Следующий код создает связь между course и department. Если объекты присоединены к контексту, course также добавляется в коллекцию department.Courses, и соответствующему свойству внешнего ключа для объектаcourse присваивается значение свойства ключа объекта department.
course.Department = department;
- Чтобы удалить связь, задайте свойству навигации значение NULL. Если платформа Entity Framework основывается на .NET 4.0, прежде чем задавать значение NULL, следует загрузить связанный конечный элемент. Например:
context.Entry(course).Reference(c => c.Department).Load();
course.Department = null;
Начиная с платформы Entity Framework 5.0, основанной на .NET 4.5, значение NULL для связи можно задать, не загружая связанный конечный элемент. Значение NULL для текущего значения можно также установить с помощью следующего метода.
context.Entry(course).Reference(c => c.Department).CurrentValue = null;
- Путем удаления или добавления объекта в коллекцию сущностей. Например, можно добавить объект типа Course в коллекцию department.Courses. Эта операция создает связь между определенным значением course и значением department. Если объекты присоединены к контексту, ссылке на department и свойству внешнего ключа для объекта course присваивается соответствующее значение department.
department.Courses.Add(newCourse);
- С помощью метода ChangeRelationshipState для изменения состояния указанной связи между двумя объектами сущности. Этот метод наиболее часто используется при работе с многоуровневыми приложениями и независимым сопоставлением (его нельзя использовать с сопоставлением на основе внешнего ключа). Кроме того, для использования этого метода необходимо дойти до узла ObjectContext, как показано в примере ниже.
В следующем примере используется связь «многие ко многим» между объектами Instructors и Courses. Вызов метода ChangeRelationshipState с параметром EntityState.Added сообщает SchoolContext, что между двумя объектами добавлена связь.
((IObjectContextAdapter)context).ObjectContext.
ObjectStateManager.
ChangeRelationshipState(course, instructor, c => c.Instructor, EntityState.Added);
Обратите внимание, что при обновлении (не только добавлении) связи необходимо удалить старую связь после добавления новой.
((IObjectContextAdapter)context).ObjectContext.
ObjectStateManager.
ChangeRelationshipState(course, oldInstructor, c => c.Instructor, EntityState.Deleted);
Синхронизация изменений между внешними ключами и свойствами навигации
При изменении связи объектов, присоединенных к контексту с помощью одного из описанных выше методов, платформе Entity Framework требуется синхронизировать внешние ключи, ссылки и коллекции. Entity Framework автоматически управляет такой синхронизацией (которую также называют исправлением связей) для сущностей POCO с прокси. Дополнительные сведения см. в разделе Работа с прокси.
Если сущности POCO используются без прокси, следует убедиться, что для синхронизации связанных объектов в контексте вызывается методDetectChanges. Обратите внимание, что следующие интерфейсы API автоматически вызывают метод DetectChanges.
- DbSet.Add
- DbSet.Find
- DbSet.Remove
- DbSet.Local
- DbContext.SaveChanges
- DbSet.Attach
- DbContext.GetValidationErrors
- DbContext.Entry
- DbChangeTracker.Entries
- Выполнение запроса LINQ для DbSet
Загрузка связанных объектов
В Entity Framework для загрузки сущностей, связанных с возвращенной сущностью определенной ассоциацией, наиболее часто используются свойства навигации. Дополнительные сведения см. в разделе Загрузка связанных объектов.
Примечание. При загрузке связанного конечного элемента зависимого объекта для сопоставления на основе внешнего ключа связанный объект загружается на основе внешнего ключа зависимого объекта, который в настоящий момент находится в памяти:
// Get the course where currently DepartmentID = 1.
Course course2 = context.Courses.First(c=>c.DepartmentID == 2);
// Use DepartmentID foreign key property
// to change the association.
course2.DepartmentID = 3;
// Load the related Department where DepartmentID = 3
context.Entry(course).Reference(c => c.Department).Load();
В независимом сопоставлении связанный конечный элемент зависимого объекта запрашивается на основе значения внешнего ключа зависимого объекта, находящегося на момент загрузки в базе данных. Однако, если связь была изменена и ссылочное свойство зависимого объекта указывает на другой основной объект, который загружается в контекст объекта, Entity Framework попытается создать связь в соответствии с определением на стороне клиента.
Управление параллелизмом
Как для внешних ключей, так и для независимых сопоставлений проверка параллелизма основывается на ключах сущностей и других свойствах сущностей, определенных в модели. При использовании конструктора Entity Framework в целях создания модели задайте для атрибута ConcurrencyModeзначение fixed для указания того, что это свойство необходимо проверять на параллелизм. При использовании Code First для определения модели используйте заметку ConcurrencyCheck для свойств, которые необходимо проверять на параллелизм. В Code First можно также использовать заметкуTimeStamp для указания того, что свойство следует проверять на параллелизм. В заданном классе может быть определено только одно свойство timestamp. Code First сопоставляет это свойство с полем в базе данных, не допускающим значения NULL.
Рекомендуется всегда использовать сопоставление на основе внешнего ключа при работе с сущностями, для которых выполняется проверка и разрешение конфликтов параллелизма.
Дополнительные сведения см. в разделе Шаблоны оптимистичного параллелизма.
Работа с перекрывающимися ключами
Перекрывающиеся ключи представляют собой составные ключи, некоторые из свойств в которых также являются частью другого ключа в сущности. Для независимых сопоставлений использовать перекрывающиеся ключи нельзя. Для изменения сопоставления на основе внешнего ключа, содержащей перекрывающиеся ключи, рекомендуется изменять значения внешнего ключа вместо использования ссылок на объекты.
No comments:
Post a Comment