Для меня данный вопрос остаётся открытым вот уже год. В обещанном примере приложения есть следующая иерархия:
Схема базы будет сгенерирована автоматически, если убрать комментарий со строки в Global.asax (ExposeConfiguration(BuildSchema)).
Код, который пытается изменить тип контента может выглядеть так:
var photo = Global.CurrentSession.Get<Photo>(2); var video = new Video(); video.FromPhoto(photo); Global.CurrentSession.Evict(photo); Global.CurrentSession.SaveOrUpdateCopy(video);
Где метод FromPhoto выглядит так:
public virtual void FromPhoto(Photo photo) { this.Id = photo.Id; this.Name = photo.Name; this.UploadDate = photo.UploadDate; }
В общем у меня не получается заставить хибернейт изменить тип контента, возможно кто-то поможет?
Ты бы на Хабре запостил :) Может найдутся ответы
ReplyDeleteВидимо предполагается, что это нелогично. Почему это фото должно становится видео? Логичнее сделать новый объект "видео", куда передать фото и настроить нужные связи и т.п. А тут ситуация, когда нужен апгрейд одной сущьности до совсем другой.
ReplyDeleteНу это просто демка, я же в прошлом посте писал когда это реально нужно
ReplyDeleteДавай сюда реальный пример, на нём и будем разбираться =)
ReplyDeletehttp://stackoverflow.com/questions/594187/nhibernate-inheritance-problem-when-saving-childs
ReplyDeleteНу я думаю там исчерпывающий ответ, особенно вот с этим я согласен:
ReplyDelete"If you are in a position to change your design, I suggest you do that - generally, you shouldn't use inheritance when the type of your specialization could change. It's much better and more convenient to introduce some kind of Role in your domain."
И ты косвенно согласился в комментах, что надо менять дизайн. Зачем же пытаться решить эту проблему, как следствие плохого дизайна?
дизайн условно плохой. И обнаружить эту плохость можно только непосредственно наткнувшись. Тем более что вопрос решается через SQL апдейты. Хотелось бы решение через ORM.
ReplyDeleteПроблема вытекает из того, что нужно сохранить его айди, а зачем это делать? Добавляем новую запись нужного типа, копируем в неё всё, что связано с больше нам ненужной и грохаем ненужную. Да это небольшой overhead, но далеко не всегда можно заставить ORM выполнять минимальный скл код, примеров масса. Придётся делать выбор или минимальный скл вызов или "оэремность".
ReplyDeleteПереписывание всех свойств, которые надо сохранить дает гору проблем. Опять же добавление одного нового свойства в Photo обязывает не забывать добавлять его переписывание, а это 100% забудут сделать.
ReplyDelete> Проблема вытекает из того, что нужно сохранить
ReplyDelete> его айди, а зачем это делать?
слай написал - чтоб ссылки на него остались рабочими.
но моё имхо такое, что на старые ссылки надо отдавать 301 Moved Permanently и новый линк. на новую сущьность. т.е. проблему решить можно чуть в другой плоскости.
Да, вопрос с сохранением линки вполне решаем редиректом. Но не решаются вопросы каскадного удаления.
ReplyDeleteа при чём тут каскадное удаление? после передвижения каментов и прочего в новую сущьность, ничего уже удалять не надо.
ReplyDeleteНу я имею ввиду что может быть очень большой граф связанных объектов. И их тупо забудут перевесить на новый объект
ReplyDeleteХороший вопрос... В моем текущем проекте возникла данная проблема. Есть некоторая сущность Company, у неё есть 2 наследника TargetCompany и PlacementCompany. При создании новой компании обязательно нужно указать её тип. Т.к. набор свойств у обеих компаний абсолютно одинаковый(единственное различие это сам тип), то в БД была создана таблица Company c полем CompanyType. В проекте был реализован класс Company и два его наследника TargetCompany и PlacementCompany. В маппингах Company было указано что поле CompanyType в БД является дискриминатором для наследников. Но в определенный момент встал вопрос о редактировании компании, и заказчику очень захотелось изменять тип Company на определенных условиях. Company имеет кучу связанных сущностей: Tasks, Events, Positions, Contacts - поэтому в лоб создать новую компанию другого типа, но со всеми параметрами старой компании есть очень трудоемкое и не очень красивое решение. На данный момент был временно подставлен костыль в ввиде SQL запроса который меняет тип компании, но вопрос остается вполне актуальным...
ReplyDelete2 Sly
ReplyDeleteкто забудет? если у тебя есть что-то типа
Video video = photo.ToVideo();
то там самое место иметь весь код по муву связанных объектов.
но если брать конкретно твой пример, то, конечно, надо просто иметь другую структуру классов. а-ля:
ViewableAndCommentableEntity, с которой будут связаны каменты и на которую будут линки. а эта энтити будет включать в себя как поле content, который может быть видео, аудио или вообще статья (текст).
2 максим
ReplyDeleteто же самое. компания должна быть полем у объектов типа Target и Placement.
ведь это логично.
Пришли к тому, с чего начинали. Что использовать композицию вместо наследования тут можно - это не вопрос. Но я не вижу принципиальной не правильности в попытке подобной смены типа. Если у нас есть студент и преподаватель. Оба они наследуют тип Human. Но студент, закончивший ВУЗ, может стать преподавателем, и при этом по прежнему наследовать Human. Везде полноценные связи "is a", почему же это не наследование?
ReplyDeleteпотому что в общем случае преподаватель может быть не только человеком, но и компьютерной системой.
ReplyDeleteвообще надо смотреть на домен. честно говоря, мало где надо иметь настолько глобальные иерархии - от "человека".
общие поля у препода и студента скорее всего заключены в "размеры", "адрес", "биология (тип крови)" - в других под-классах.
кстати я всё чаще и чаще ловлю себя на мысли, что реальные бизнес-задачи редко требуют иерахий наследования.
а вот чисто компьютерные (вспомогательные, типа разработка ИДЕ, Редакторов) наоборот требуют.
такие дела.
Может я не в тему.
ReplyDeleteНо Харьковчанам респект.
2 СОТОНА:
ReplyDelete>кстати я всё чаще и чаще ловлю себя на мысли, что >реальные бизнес-задачи редко требуют иерахий >наследования.
Аналогично, меня это пугало, оказывается зря =)
2 Sly:
Композиция это отлично, наследование замечательно =) В конкретной ситуации действительно композиция решает проблему, но как я понимаю вопрос стоит чисто теоретически "а вот как сделать такую штуку в nHibernate", т.е. здесь скорее сыграла своё пытливость ума и так сказать geek-нутость =) Я прав?
Чем мне не нравится композиция - она не позволяет избегать операторов if. Именно из-за этих причин я предпочитаю почаще использовать именно схему наследования. Как правило проблем с этим не возникает, ну кроме описанной тут :)
ReplyDelete>она не позволяет избегать операторов if.
ReplyDeleteда прямо таки.
типа из-за композиции полиморфизм отменили :)
если чё, то вместо
foreach (с in content) {
c.show()
с.showComments()
}
у тебя будет
foreach (с in content) {
c.content.show()
c.showComments()
}
content - колекция фоток, статей, видео и прочего.
пример притянут зауши, просто чтобы показать, что никаких if'ов. :)
c.content - поле, для нашей композиции, которое уже есть или видео или фотка или статья.
ReplyDeleteИли я чего то не понимаю, или для поля content тоже нужна будет иерархия наследования?
ReplyDeleteну достаточно реализовывать общий интрефейс :)
ReplyDeleteно суть же не в том, что совсем не надо наследования (хотя в данном случае можно и без него), а в том, что композиция вполне работает и цепочки if'ов или switch'и не нужны.
а самая уже суть, конечно, в том, что у тебя для связи объектов есть связующий класс, который служит именно для связи. а не "для хранения контента" и "для хранения коментов к контенту". типа, single responsibility principle...