NHibernate - у меня их много, но я хочу только одну!

У меня есть пользователь, который может иметь много электронных писем. Это отображается через коллекцию List (предоставленную IEnumerable Emails для пользователя). Для каждого Пользователя одно из Электронных писем будет Первичным (свойство Boolean IsPrimary в Электронной почте).

Как я могу получить основное электронное письмо от пользователя, если NHibernate не загружает каждое электронное письмо для пользователя?

У меня есть следующие два объекта с соответствующей таблицей для каждого

public class User
{
   private readonly IList<Email> _emails;

   public virtual int Id { get; private set; }
   public virtual IEnumerable<Email> Emails { get { return _emails; } }
   // public virtual Email PrimaryEmail { get; set; } - Possible somehow ?
}
public class Email
{
   public virtual int Id { get; private set; }
   public virtual String Address { get; set; }
   public virtual Boolean IsPrimary { get; set; }
   public virtual User User { get; set; }
}

Могу ли я сопоставить свойство «Email PrimaryEmail» и т. д. для пользователя с электронной почтой, для которой каким-то образом установлено «IsPrimary = 1»? Может быть, используя формулу Sql? вид ? отношения один к одному? или другой способ?

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

Используя формулу Sql, можно ли сохранить свойство «PrimaryEmail» для пользователя в актуальном состоянии, если я установлю для свойства IsPrimary текущего основного адреса электронной почты значение false, а затем установлю для свойства PrimaryEmail адрес электронной почты, который должен быть новым основным адресом электронной почты и установить для параметра IsPrimary значение true ? Будет ли NHibernate отслеживать изменения в «старом/текущем» основном электронном письме, загруженном формулой Sql? Как насчет кеша 1-го уровня и кеша 2-го уровня при использовании SqlFormula?

Я не знаю, может ли это работать с использованием View ? Тогда я предполагаю, что электронная почта может быть сопоставлена ​​​​как компонент? Будет ли это работать при обновлении данных электронной почты при загрузке из представления?

Есть ли способ лучше ?

Поскольку у меня есть двунаправленные отношения между пользователем и электронной почтой, я мог бы во многих случаях, конечно, запросить основное электронное письмо, а затем использовать свойство «Пользователь» в электронной почте, чтобы получить пользователя (вместо обратного пути — перехода от пользователя к основной адрес электронной почты)

Надеюсь, кто-нибудь сможет помочь?


person MartinF    schedule 09.04.2010    source источник


Ответы (2)


На первый взгляд, я думаю, мне бы хотелось убедиться, что PrimaryEMail всегда является ссылкой на один из объектов EMail в коллекции (один из способов сделать это — получить/установить полностью «на лету»). С общедоступным дизайном, как у вас, вам придется перехватывать изменения с помощью обработчика событий в электронной почте и/или коллекции. Новый основной объект электронной почты (что-то в коллекции, которую вы повышаете до основной) будет знать о своей родительской коллекции или пользователе, поэтому он должен иметь возможность найти текущий основной объект, чтобы сделать его вторичным.

Альтернативы включают в себя то, что IsPrimary не является общедоступным набором или даже вообще не выставляется на всеобщее обозрение (email.IsPrimary будет заменен на email == user.PrimaryEMail). Метод set PrimaryEMail может принимать только объект EMail, который уже находится в коллекции.

Я сделал это только в ручных классах ORM и не смог найти канонический метод для выполнения этого довольно распространенного сценария в NHibernate. Там должен быть один.

person Cade Roux    schedule 09.04.2010

Прежде всего. Почему вы используете IEnumerable там? Вы хотите запускать запрос каждый раз при доступе к этому свойству? И почему у него есть общедоступный сеттер?

Мне кажется, вы хотите, чтобы это был либо IList, либо ICollection. Наличие списка имело бы больше смысла, поскольку я бы добавил два метода:

User.SetPrimary(int index)
User.GetPrimary()
User.ICollection Emails { get; protected set; }

Email.IsPrimary { get; protected set; }

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

person Ramon Smits    schedule 09.04.2010
comment
Здравствуйте, спасибо за ваш ответ. У меня есть частное поле IList‹Email›, отображенное в фоновом режиме, но оно доступно общедоступному IEnumerable‹Email›. Кроме того, сеттер, конечно, должен быть закрытым/защищенным - это не мой фактический код, а быстрый пример, который я написал, чтобы сделать его более простым (я обновлю его). В этом случае загрузка всех электронных писем для их повторения может работать, но как насчет сценария с альбомом/изображениями, где мне просто нужно одно изображение вместо загрузки, может быть, 100 изображений, чтобы просто найти одно? Я хотел бы, чтобы он не загружал все из базы данных, а получал только то, что нужно. - person MartinF; 09.04.2010
comment
Такая ленивая загрузка данных изображения. Это зависит от того, как вы хотите получить доступ к фотографии. Если у вас уже есть ключ, то логичным будет доступ напрямую к фотозаписи. Например, следующий URL-адрес /user/photos/photo/photoId /user/photos/album/albumId Кстати... хотя пользователь является владельцем электронной почты, это не делает его частью пользователя. Таким образом, коллекция электронных писем в пользовательском классе моделируется неправильно. Просто отразите это на реальной жизни. Вы являетесь владельцем своего дома и/или автомобиля, но ваш дом или автомобиль не являются частью вас. Если только случается, что у вас есть отношения с вашей машиной или домом. - person Ramon Smits; 14.04.2010
comment
Это часть пути к тому, как я бы это реализовал. Проблема в том, что потребляющий код может напрямую обновлять свойство IsPrimary электронной почты, минуя метод SetPrimary класса User, обходя решение и быстро все портя. - person Remi Despres-Smyth; 12.07.2013