Расширьте / измените классы NHibernate во время выполнения
Извиняюсь, если уже есть точный ответ, но я его не нашел. Я использую NH3, и у меня есть сценарий использования, где я хочу добавить Set в любую сущность, класс которой реализует определенный интерфейс. У меня есть класс построителя конфигурации, поэтому я могу внести эти изменения до создания фабрики сеансов.
Учитывая этот сокращенный пример:
public class Person : IHasExtraItems
{
public Person()
{
this.ExtraItems = new HashSet<ExtraItem>();
}
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual DateTime Birthdate { get; set; }
public virtual ICollection<ExtraItem> ExtraItems { get; protected set; }
}
public class ExtraItem
{
public virtual Guid Id { get; set; }
}
И этот пример сопоставления:
<class name="Person">
<id name="Id">
<generator class="guid"/>
</id>
<property name="Name"/>
<property name="Birthdate"/>
<set name="Extra" table="PersonExtraItems" cascade="all">
<key column="PersonId"/>
<many-to-many column="ExtraItemId" class="ExtraItem" unique="true" />
</set>
</class>
Так как я хочу иметь возможность применять эту функциональность ко многим классам прозрачно - просто путем реализации интерфейса - я не хочу помещать "ExtraItem" в отображение. Вместо этого я хочу добавить его во время выполнения. Так что, если я удаляю свойство из сопоставления xml, как я могу добавить это во время выполнения?
Вот это описание того типа изменений, которые я пытаюсь внести: http://ayende.com/Blog/archive/2008/05/01/Dynamic-Mapping-with-NHibernate.aspx
Но он не отображает множество на множество, и мой слабый мозг не смог расшифровать представление отображения в памяти, которое nhibernate использует для создания эффекта. Это самое близкое, что я сделал, основанный на попытке сделать свойства видимыми в отладчике, чтобы они соответствовали
foreach (var cls in cfg.ClassMappings)
{
if (typeof(IHasExtraItems).IsAssignableFrom(cls.MappedClass))
{
NHibernate.Mapping.Property property = new NHibernate.Mapping.Property();
NHibernate.Mapping.Set value = new NHibernate.Mapping.Set(cls);
value.Role = cls.EntityName + ".ExtraItems";
value.IsGeneric = true;
var table = new Table();
table.Name = cls.MappedClass.Name + "ExtraItems";
value.CollectionTable = table;
value.GenericArguments = new Type[] { typeof(ExtraItem) };
value.IsOptimisticLocked = true;
value.IsLazy = true;
mappings.AddCollection(value);
property.Value = value;
property.Name = "ExtraItems";
property.PersistentClass = cls;
property.Cascade = "all";
cls.AddProperty(property);
}
}
В тесте это приводит к ошибке времени выполнения, поскольку ключ имеет значение null, однако версия, отображенная в формате XML, работает и выглядит более или менее идентично в момент внесения изменений.
Бонусные баллы: я хочу многим ко многим именно потому, что мне нужен объединенный стол. Это позволяет мне сопоставить сущность с расширяющимися данными с истинными внешними ключами для производительности. ExtraItems действительно должен быть типом значения, а не истинной сущностью, но я не мог понять, как отобразить это, даже в XML.
Бонусные баллы, часть 2: Могу ли я сделать это с помощью confORM? Я не хочу переключать все мои существующие сопоставления на confORM, и я не смог найти пример смешивания confORM с обычными XML-отображениями, не говоря уже об изменении существующих отображений. Fluent был бы другим вариантом, но я использую NH3, и я не думаю, что Fluent пока поддерживает это.
Заранее спасибо!
РЕДАКТИРОВАТЬ Я вполне уверен, что моя проблема в том, что я не определяю элементы набора. Однако я не могу понять, как правильно определить элементы набора.
1 ответ
Для NH3 существуют свободные версии, так что вы можете использовать его (и я), и если вы используете свободный, вы можете очень легко сделать это по соглашению. Вы упоминаете об этом в разделе о бонусных баллах, так что, может быть, вам стоит взглянуть на это по-другому?