Войдя в мир NHibernate менее года назад, я все еще развиваю свою
"личная" лучшая практика и архитектурные решения в этой области ... теперь я сталкиваюсь с
довольно простой вопрос, по которому я хотел бы, чтобы кто-то
больше опыта.
Сценарий следующий: прямые родительские / дочерние отношения, хранящиеся в ISet на родительской стороне.
Классы:
public class IDPersisted<IdentifierType>
{
private IdentifierType _id;
public IDPersisted()
{
_id = default(IdentifierType);
}
public IDPersisted(IdentifierType id)
{
_id = id;
}
}
public class SportCenter : IDPersisted<Guid>
{
...
private ISet<Field> _fields = new HashedSet<Field>();
public bool AddField(Field field)
{
field.SportCenter = this;
return _fields.Add(field);
}
public bool RemoveField(Field field)
{
field.SportCenter = null;
return _fields.Remove(field);
}
...
}
public class Field : IDPersisted<Guid>
{
public Field(String name)
{
Name = name;
}
public String Name { get; set; }
public SportCenter SportCenter { get; set; }
...
}
Как видите, у меня есть базовый класс, реализующий общий оператор Identifier, операторы Equals / GetHashCode и == /! = Полагаются на поле ID, которое считается неизменным в течение жизни экземпляра класса. Классы SportCenter (родительский) и Filed (дочерний) сохраняются с идентификатором Guid. SportCenter содержит коллекцию (фактически, Набор) экземпляров Field, управляющих двунаправленной связью в методах Add / RemoveField.
Отображения:
<class name="SportCenter" table="SportCenters" lazy="false">
<id name="ID" column="SportCenterID" >
<generator class="guid.comb" />
</id>
...
<set name="Fields" table="Fields" inverse="true" lazy ="true" cascade="all-delete-orphan" access="field.camelcase-underscore">
<key column="SportCenterID" />
<one-to-many class="Field" />
</set>
</class>
<class name="Field" table="Fields" lazy="false">
<id name="ID" column="FieldID" type="Guid">
<generator class="guid.comb" />
</id>
<property name="Name" column="Name" type="String" not-null="true" />
...
<many-to-one name="SportCenter" column="SportCenterID" class ="SportCenter" not-null="true" lazy="proxy" />
</class>
Я принял все основные советы, которые вы получаете для отображения такого рода отношений: inverse = "true", Set не доступен напрямую (access = "field"), каскадные и ненулевые ...
В моем BLL у меня есть метод для создания нового поля внутри определенного SportCenter:
public void CreateField(FieldDTO fieldDTO, Guid sportcenterID)
{
// Retrieve the SportCenter
SportCenter sportcenter = SportCentersDAO.GetByID(sportcenterID);
// Prepare the new Field object
Field field = new Field(fieldDTO.Name);
...
// Add the new field to the SportCenter
sportcenter.AddField(field);
// Save the SportCenter
SportCentersDAO.Save(sportcenter);
}
Что происходит, когда я создаю новый экземпляр Field, его ID устанавливается на Guid.Empty
(то есть все нули), тогда я вызываю AddField, и поле добавляется в Set с этим ID ... тогда, только в SportCentersDAO.Save
вызов реального Guid назначен field.ID.
Это нарушает одно из правил, которые вы можете найти в каждой спецификации / документации / книге о NHibernate, а именно:
Никогда не меняйте идентификатор экземпляра, пока он хранится в ISet (поскольку идентификатор - это свойство, с помощью которого экземпляры сравниваются с помощью Equals (), как я написал выше).
Предоставление в поле значения Guid для идентификатора перед добавлением его в набор приведет меня к злым «назначенным» идентификаторам и, если вам придется ответить, не полагаться на идентификатор для Equals/GetHashCode
и найти естественную модель связанный ключ ... ну, я не верю, что когда-либо обнаруживал в этих свойствах, которые обеспечивают неизменность / уникальность, которых заслуживает "ключ".
Я что-то не так делаю !? Что ты думаешь по этому поводу?
Заранее спасибо, Питер.