Гугл подсказал мне, что блог находят в основном при поиске того, как замапить различные виды наследования используя Fluent Nhibernate. Попробую осветить этот вопрос.
Nhibernate поддерживает 3 способа реализации наследования. Различаются они количеством необходимых для этого таблиц. Далее будут рассмотрены 2 из них подробнее.
Table per class hierarchy
В данной схеме для всей иерархии классов используется одна таблица. Рассмотрим пример со следующей моделью:
Для хранения такой структуры будет достаточно одной таблицы с полями Id, Name, UploadDate, WhoIsOnPicture, Lenght, Type. Стоит обратить внимание на то, что поле Type используется Nhibernate’ом для того, чтобы узнать какой конкретный тип находится в конкретной строке. Итак маппинг будет выглядеть следующим образом:
public class ContentMapping: ClassMap<Content> { public ContentMapping() { Id(x => x.Id).GeneratedBy.Native(); Map(x => x.Name).Length(200).Not.Nullable(); Map(x => x.UploadDate).Not.Nullable(); DiscriminateSubClassesOnColumn("ContentType"); } } public class PhotoMapping : SubclassMap<Photo> { public PhotoMapping() { Map(x => x.WhoIsOnPicture); DiscriminatorValue("Photo"); } } public class VideoMapping: SubclassMap<Video> { public VideoMapping() { Map(x => x.Length); DiscriminatorValue("Video"); } }
Генерируемый XML довольно громоздкий, и полностью приводить его я не буду. Важно лишь то, что сформирован маппинг, и в нем используются теги subclass для photo и video.
Недостатком данной схемы является то, что в таблице Content колонки WhoIsOnPicture и Length обязательно должны позволять сохранять NULL.
Table per subclass
Очень радует, что для того, чтобы использовать этот подход, достаточно просто убрать упоминания Discriminator из классов, маппинг будет абсолютно таким же:
public class ContentMapping: ClassMap<Content> { public ContentMapping() { Id(x => x.Id).GeneratedBy.Native(); Map(x => x.Name).Length(200).Not.Nullable(); Map(x => x.UploadDate).Not.Nullable(); } } public class PhotoMapping : SubclassMap<Photo> { public PhotoMapping() { Map(x => x.WhoIsOnPicture); } } public class VideoMapping : SubclassMap<Video> { public VideoMapping() { Map(x => x.Length); } }
Этот маппинг приведет к использованию joined-subclass элементов.
Как-то скудненько, где трейтий тип наследования? не дописал что-ли?
ReplyDeleteНе могли бы вы выложить пример кода? Т.к. при попытке реализовать стратегию "Table per subclass", аналогично приведенному примеру, sql-код при сохранении/изменении экземпляра класса-потока генерируется для родительской таблицы...
ReplyDeleteКонечно, сейчас займусь
ReplyDeleteдополнение к вышестоящему комментарию (предвидя вопрос), функция DiscriminateSubClassesOnColumn у меня отсутствует, как и полагается при "Table per subclass". Но тем не менее sql-код пытается писать в родительскую таблицу. Вот мой код маппинга:
ReplyDeletepublic class MaterialMap : ClassMap
{
public MaterialMap()
{
Table("MATERIAL_AAA");
Not.LazyLoad();
Id(x => x.ID).Column("MATERIAL_ID")
.GeneratedBy.Sequence("MATERIAL_SQ");
}
}
public class RealMaterialMap : SubclassMap
{
public RealMaterialMap()
{
Table("MATERIAL");
Not.LazyLoad();
}
}
при сохранении объекта типа RealMaterial генерируется следующий SQL:
could not insert:
INSERT INTO MATERIAL_AAA (MATERIAL_ID) VALUES (?)
Заранее благодарен за помощь!!!
Извиняйте, жестко затупил, при "Table per subclass", только доп. поля кладутся в дочерние таблицы... Представлял себе по-другому.
ReplyDeleteХоть бы структуру таблиц в базе выложил.
ReplyDeleteСогласен: не хватает структуры таблиц в БД для большей наглядности.
ReplyDeleteСтруктуру таблиц специально не выкладывал потому что пост только о FluentNhibernate. При желании по маппингам можно сгенерировать базу.
ReplyDeleteGood readd
ReplyDelete