поставить только тип ключа (id) или тип класса для FK в сущностях, за и против - PullRequest
3 голосов
/ 27 сентября 2010

Я видел 2 типа сущностей, таких как:

public class Person
{
    public int Id {get;set;}
    public string Name {get;set;}
    public Country Country {get;set;}
}

и вот так:

public class Person
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int CountryId {get;set;}
}

Я думаю, что второй подход более легкий, и вы получаете связанные данные только в случае необходимости;
какой из них вы считаете лучше?

Ответы [ 6 ]

1 голос
/ 28 сентября 2010

STOP!

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

Если у вас включена отложенная загрузка (по умолчанию она включена), вызов:

int countryId = person.Country.Id;

... не приведет к попаданию в базу данных для извлечения сущности Country.NHibernate вернет динамический прокси вашего Клиента, а не фактического Клиента.Из-за прокси, попадание в базу данных будет происходить только при первом доступе к свойству в вашей сущности Customer, но NHibernate достаточно умен, чтобы понять, что person.Country.Id аналогичен доступу к внешнему ключу ID вашего лицатаблица, которая загружается в любом случае.

Однако следующий код:

string countryName = person.Country.Name;

... попадет в базу данных, вызов свойства 'Name' загрузит весь Customerinstance.

Это поведение предполагает, что вы настроили свое отображение следующим образом:

<many-to-one name="Country" class="Country" column="Country_ID" lazy="proxy" />

(обратите внимание, что по умолчанию используется lazy = "proxy").

Простопоставьте, нет необходимости сопоставлять внешние ключи в модели вашего домена с NHibernate.

1 голос
/ 27 сентября 2010

За исключением некоторых странных крайних случаев, для второго дизайна нет веских причин.

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

1 голос
/ 27 сентября 2010

Хороший вопрос! Для меня

public List<Person> GetPersonsLivingIn(int countryId) {
  return ObjectContext.Persons.Where(x => x.CountryId == countryId).ToList();
}

выглядит так, как будто он работает таким образом, не зная обо всех магических (неплотных) абстракциях, которые могут присутствовать в ORM, которые заставят x => x.Country == country работать. Я пришел из Linq2Sql, где у меня были некоторые проблемы с первым при передаче объектов, созданных в разных контекстах объектов.

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

public List<Person> GetPersonsLivingIn(Country country) {
  return ObjectContext.Persons.Where(x => x.CountryId == country.CountryId).ToList();
}

, который имеет более чувствительный интерфейс ОО, но все равно выглядит так, как будто он работает без магии.

1 голос
/ 27 сентября 2010

Существует два аспекта: платформы и трафик, описанные ниже ...

Все в платформе Microsoft

В многоуровневых решениях, где конечным клиентом является Silverlight ивы собираетесь поделиться сгенерированным кодом через службы RIA или у вас есть клиент WPF со службами RIA WCF; первое решение дает вам лучший дизайн.

Конечный клиент не от Microsoft

Если ваш конечный клиент не является клиентом Microsoft, например Flex / Flash, Java или любым интеллектуальным клиентом на основе ajax, то первая модель не будет полезнатак как он должен отслеживать себя (самообследование объектов).Вторая модель здесь предпочтительна.

Приложения с низким трафиком

Если сетевой трафик не так важен и ваш дизайн программного обеспечения более важен, или у вас средне масштабируемая средняяшины для кэширования и т. д., такие как App Fabric и т. д., первое хорошее решение, которое улучшит дизайн.

Приложения с высоким трафиком

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

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

1 голос
/ 27 сентября 2010

Взятый по номиналу, первый пример модели богатой предметной области, а второй подход, основанный на данных.Разрешение моделей с расширенными доменами является одним из основных преимуществ ORM.

Единственная причина, по которой я бы включил CountryId (вместо страны или в дополнение к ней), заключается в оптимизации для некоторых оченьконкретная проблема производительности.Даже тогда я бы подумал дважды.А оптимизация - это то, о чем вам не следует слишком много думать на начальном этапе проектирования.Что не так с Person.Country.Id?(Предполагая, что идентификатор вам нужен вообще, а не только инфраструктура).

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

1 голос
/ 27 сентября 2010

Зависит от того, что вы хотите.Если вы хотите получить только идентификатор страны, перейдите ко второму варианту.Если вы действительно хотите использовать свойства навигации и / или отложенную загрузку, перейдите к первому варианту.

Лично я использую Entity Framework и объединяю варианты один и два:

public class Person
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int CountryId {get;set;}
    public Country Country {get;set;}
}

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

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