2010-04-17 2 views

ответ

18

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

+2

Что было бы полезно иметь сложный тип вместо обычных скалярных свойств? – emzero

+0

@emzero Я думаю, их много, это в основном OOD. Вы не можете определить метод get в адресе или передать адресный объект другим методам при отправке груза. Он также следует методу DRY. Предположим, что вы выполняете переопределение ToString(), вам нужно сделать это только один раз для всех классов, имеющих адрес. –

+0

Не затрудняет ли это выполнение операции по всем адресам всех разных таблиц? Что делать, если я хотел добавить данные геолокации, или очистить все форматирование адресов и т. Д.? Разве это не будет намного проще с отдельной таблицей? Или вы можете сделать что-то вроде repo.ComplexTypes.ToList() –

0

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

+0

Агрегированный корень может содержать объекты, имеющие ключи. Они просто принадлежат к совокупному корню. –

10

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

Сложные типы не поддерживают ленивую загрузку, по крайней мере, в 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, а затем просто добавьте их в объект Person. У вас больше не будет аккуратного адресного префикса, но не потерять сон.

Но подождите, есть еще!

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

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

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

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

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

public class GenericModelFilter<T> : where T : EntityModel 

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

Двигаясь, вы добавить метод в классе, который базировался на выбор пользователя можно создать выражение, которое можно использовать с LINQ для фильтрации любого класса Entity

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; 

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

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