Сложный тип Entity Framework против создания нового Entity - PullRequest
29 голосов
/ 17 апреля 2010

Я читаю об Entity Framework 4.0, и мне было интересно, почему я должен создавать сложный тип, а не новый Entity (Таблица) и связь между ними?

Ответы [ 3 ]

19 голосов
/ 17 апреля 2010

Прекрасным примером является адрес. Использование сложного типа для адреса намного проще, чем для нового объекта. Со сложными типами вам не нужно иметь дело с первичным ключом. Подумайте о доступе к адресу: сколько общих типов объектов будет иметь адрес (бизнес-единицы, люди, места) Представьте, что вы заполняете адреса многих людей и нуждаетесь в том, чтобы установить ключ для каждого из них. Со сложными типами вы просто получаете доступ к внутренним свойствам их типа, и все готово. Вот ссылка MSDN примера. http://msdn.microsoft.com/en-us/library/bb738613.aspx

12 голосов
/ 23 ноября 2013

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

Сложные типы не поддерживают отложенную загрузку, по крайней мере, в EF 4.3. Давайте возьмем адресную ситуацию в качестве примера. У вас есть таблица Person с 15 столбцами, 5 из которых содержат адресную информацию для определенных лиц. Он имеет 50 тыс. Записей. Вы создаете сущность Person для таблицы со сложным типом Address.

Если вам нужен список имен всех лиц в вашей базе данных, вы должны сделать

var records = context.Persons;

, который также включает в себя адреса, добавляя значения 5 * 50k в ваш список без причины и с заметной задержкой. Вы можете загрузить только нужные вам значения в анонимном типе с

var records = from p in context.Persons
              select new {
                LastName = p.LastName,
                FirstName = p.FirstName,
              }

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

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

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

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

Но подождите, это еще не все!

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

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

class EntityModelComparer<T> : IEqualityComparer<T> where T : EntityModel

, который вы затем можете использовать с Distinct () для фильтрации дубликатов из любого IQueryable типа T, где T - класс сущности. Сложный тип не может наследоваться от EntityModel, потому что у него нет свойства ID, но это нормально, потому что вы все равно не будете использовать его в отличие от него.

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

public class GenericModelFilter<T> : where T : EntityModel

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

Продвигаясь вперед, вы добавляете в свой класс метод, который на основе выбора пользователя может создать выражение, которое вы можете использовать с linq для фильтрации любого класса сущностей

Expression<Func<T, bool>> GetPredicate() { ... }

так что теперь вы можете сделать что-то вроде этого:

personFilter = new GenericModelFilter<Person>();
companyFilter = new GenericModelFilter<Company>();
addressFilter = new GenericModelFilter<Address>(); //Complex type for Person

...

var query = from p in context.Persons.Where(personFilter.GetPredicate())
            join c in context.Companies.Where(companyFilter.GetPredicate()) on p.CompanyID = c.ID
            select p;

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

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

0 голосов
/ 15 февраля 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...