tags:

views:

30

answers:

3

I've already read http://stackoverflow.com/questions/478296/nhibernate-changing-sub-types and I don't find that satisfactory to my situation.

My system allows users to schedule jobs. Schedules can be set up with different types of schedule criteria (Once only, Daily, Weekly, Monthly by day of month, and Monthly by week of month). Each of these have very different data and behavior. It is perfectly valid for a user to change a schedule from one criteria type to another.

I attempted to make this work by grabbing the schedule id that was saved previously, creating a new instance of the schedule with the new type, setting the id, and saving. All of the data was updated as expected, except, of course, the discriminator.

Changing my model would be an absolute last resort.

At this point, I am looking at saving the new criteria (with a new id) and updating the references to it, then deleting the old criteria.

Does someone have a better idea?

A: 

Have you tried modifing your disciminator mapping to add force=true like the following hbm.xml element

<discriminator column="DiscriminatorColumnName" force="true" />

Nathan Fisher
Hmm... I'd like to try that but am having trouble with the discriminator mappings in Fluent-NHibernate
Will
A: 

Since you're already bending the NHibernate view of object identity, why don't you just update it outside of NHib using some custom SQL?

My preferred solution would be to update my model, but you've said that that's a last resort for you.

John Rayner
Out of curiosity, how would you propose to update the model?
Will
Choice 1: create a new schedule object of the correct type, and key the job into the new schedule (i.e. it will get a new PK value).Choice 2: create a "super-schedule" object which can fire on any or all of daily, weekly, monthly and so on. IOW there is no DailySchedule class or a WeeklySchedule class. Changing a schedule then becomes a matter of updating the relevant bits on this object, rather than trying to change the object's type.
John Rayner
A: 

If you want to use NHibernate, then the concession you must make is:

Write object-oriented code.

If your particular case is arduous to express in an object-oriented manner, then you should not be using NHibernate for that case.

For your case, you should:

  • create a new instance of a class deriving Schedule, and permit it to have a new ID
  • copy the relevant properties from the old Schedule instance
  • delete the old Schedule instance from the Session and ensure that the Job instance in question does not reference it
  • add the new Schedule instance to the Session and ensure that the Job instance in question references it

This will end up, at the database level, as a delete and insert, rather than an update.

This is not a last resort. This should have been your first resort. This is the right way to do it from an object-oriented perspective.

Justice
Essentially this is what I am doing: * create the new ScheduleCriteria and populate it from the UI * identify the id of the old ScheduleCriteria * save the Schedule with it's new ScheduleCriteria * delete the old ScheduleCriteria by id
Will
By the way, what makes you think this isn't object oriented? I was able to use this method with my existing model without making any changes.The point of the exercise was to try to make it more convenient to persist my objects by performing an update instead of the delete+insert. What's relevant here is the mapping between my object and relational models; hence, ORM.
Will
With NHibernate, you don't persist your objects. With NHibernate, you write object-oriented code and trust NHibernate magically to persist your objects as appropriate. So that means you should work within the semantics of the language, C#. In C#, you cannot change the type of an object. When using NHibernate, then, you should not try to change the type of an object.
Justice