0

У меня есть устаревшая база данных, которая имеет несколько таблиц, которые были разработаны с использованием Polymorphic Associations. По полиморфным ассоциациям я имею в виду, что эти таблицы могут быть дочерними из разных таблиц в соответствии с столбцом ObjectType.Полиморфные ассоциации в инфраструктуре Entity

Пример:

  • Documents таблица имеет DocumentID (первичный ключ идентичности), некоторые другие столбцы и 2 специальные столбцы называемые ObjectType и ObjectID.
  • Если ObjectType='STUDENT', ObjectID указывает на Students стол.
  • Если ObjectType='TEACHER', ObjectID указывает на таблицу Teachers и т.д.

Это похоже на this design (как описано в «нет внешнего ключа подхода») или this one (описанного в качестве анти-паттерна). И, очевидно, есть ограничений внешнего ключа на этих столбцах (AFAIK без базы данных допускает такую ​​зависимость).

Я пишу новый уровень доступа к данным, используя Entity Framework 6 (сначала код с Fluent API), который должен работать бок о бок с существующим кодом. Поскольку эта структура базы данных была развернута сотнями разных клиентов (каждая из которых имеет различную базу кода и различные настройки базы данных), изменение структуры существующих таблиц не является вариантом.

Мой вопрос: Как сопоставить эти Полиморфные ассоциации в моей первой модели кода EF?


EDIT: Кажется, что я пытался разработать иерархию классов на неправильных сущностей. Я понял, что у меня было много «GenericChildTables» (например, Documents), которые должны указывать на (несуществующий) объект, который будет иметь составной ключ ObjectType + ObjectID. И затем я пытался создать этот новый объект (назовем его «BusinessObject») и сопоставить мои основные объекты (учащиеся, учителя и т. Д.) Как подтипы этого объекта BusinessObject.

Этот дизайн, вероятно, был просто неправильным, и, возможно, совершенно невозможно, потому что эта новая таблица, которую я создавала (BusinessObject), зависела от StudentID/TeacherID и т. Д., Поэтому она не могла быть родителем этих таблиц. Используя некоторые уродливые обходные пути, я мог бы создать этот BusinessObject как одно дочерний для каждого основного объекта и сопоставить эти BusinessObjects с полиморфными таблицами, и он работал действительно, но в совершенно неправильном дизайне.

Тогда я увидел Gert Ardold's question и понял, что должен быть выполнен в виде иерархии классов НЕ был Студенты/Преподаватели/и т.д. (сгруппированных в общей сущности), но каждый из этих ChildTables, которые держали в руках различные подтипы в соответствии с дискриминатор ObjectType - это те типы, которые должны быть разделены на подтипы. См. Мое решение по моему собственному ответу ниже.

+2

[Здесь] (http://stackoverflow.com/q/13953675/861716), как я это сделал, используя сначала базу данных, но также описал, как я не смог перенести его в код-первый. –

+0

@GertArnold Вы пробовали что-то вроде этого https://gist.github.com/mauriciolobo/40a4fc6017539c79135bf62f57ee80f1? – drizin

+0

Нет, это не правильная модель (два внешних ключа). –

ответ

1

Кажется, что я пытался создать иерархию классов на неправильных объектах. Я понял, что у меня было много «GenericChildTables» (например, Documents), которые должны указывать на (несуществующий) объект, который будет иметь составной ключ ObjectType + ObjectID.И затем я пытался создать этот новый объект (назовем его «BusinessObject») и сопоставить мои основные объекты (учащиеся, учителя и т. Д.) Как подтипы этого объекта BusinessObject.

Затем я увидел Gert Ardold's question и понял, что правильная схема наследования НЕ была связана с группировкой студентов/учителей/и т. Д. В супертип, но о разделении этих таблиц GenericChildText на несколько подтипов.

Я буду использовать таблицу «Документы» в качестве примера, чтобы показать, как я преобразовал эти таблицы GenericChildTables в TPH и как я сопоставил свои основные объекты (учащиеся, учителя и т. Д.) С коллекциями этих подтипов.

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

public class StudentDocument : Document 
{ 
    public Student Student { get; set; } 
    public int StudentID { get; set; } 
} 
public class TeacherDocument : Document 
{ 
    public Teacher Teacher { get; set; } 
    public int TeacherID { get; set; } 
} 
modelBuilder.Entity<Document>() 
.Map<StudentDocument>(m => { 
    m.Requires("ObjectType").HasValue("STUDENT"); 
}) 
.Map<TeacherDocument>(m => { 
    m.Requires("ObjectType").HasValue("TEACHER"); 
}); 

Затем я добавил навигационные свойства моих основных классов (Студент и учителей), указывая на подтипы созданных:

partial class Student 
{ 
    public virtual ICollection<StudentDocument> Documents { get; set; } 
} 
partial class Teacher 
{ 
    public virtual ICollection<TeacherDocument> Documents { get; set; } 
} 

Я создал отображения для отношений Student.Documents и Teacher.Documents. Пожалуйста, обратите внимание, что я использую свойства StudentID и TeacherID, но они Специальные условия отображаются в столбце ObjectID:

var sl = modelBuilder.Entity<StudentDocument>(); 
sl.Property(t => t.StudentID).HasColumnName("ObjectID"); 
sl.HasRequired(t => t.Student).WithMany(t => t.Documents).HasForeignKey(d => d.StudentID); 

var al = modelBuilder.Entity<TeacherDocument>(); 
al.Property(t => t.TeacherID).HasColumnName("ObjectID"); 
al.HasRequired(t => t.Teacher).WithMany(t => t.Documents).HasForeignKey(d => d.TeacherID); 

Наконец, я удалены из базового типа (Документ) собственности ObjectType, потому что это тип дискриминатора, и должен использоваться только внутри страны (не может быть выставлен на класс).
Я также удален от базового типа ObjectID, потому что это должно отображаться только по подтипам (отображается соответственно как StudentID и TeacherID).

И все работает как шарм!

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

+0

У меня была игра с ним, и это, казалось, создало TPC или TPH, но без назначений FK. Какова была полученная схема? – Mardoxx

+0

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

+0

Ах, да, да! Вы так говорите в первом предложении :) – Mardoxx