J. Ed
J. Ed

Reputation: 6742

nhibernate transform an entity from one type to the other: how to handle collections?

I have a very similar situation to what's described in this question:
Engineer and Manager both inherit from Contact, and Engineer can be promoted (or demoted, depending on your perspective) to Manager.

difference is- I log all orders submitted by a contact.
meaning- my Contact class has a IList<Order> Orders property, which can consist of 100,000s of orders. (before you ask- obviously this property isn't ever loaded into memory, it's just the opposite end of the Contact OrderSubmitter property of Order).

I like the idea of a 'copy constructor' of sort, suggested by @Jamie Ide.
the question is- can I change the referemce of the Order objects without loading them to memory?

[EDIT]
yes, I can- using HQL update.
However, this creates a different problem- I'm trying to create an entity and have other entities referencing it in the same transaction. meaning:

Manager manager = new Manager(engineer);
session.Save(manager);
session.CreateQuery("update Order set OrderSubmitter = :manager where OrderSubmitter = :engineer")
  .SetParameter("manager",manager)
  .SetParameter("engineer",engineer)
   .ExecuteUpdate();
session.Transaction.Commit();

however- the ExecuteUpdate occurs immidiately, whereas the Manager entity is only saved on 'commit'.
This, of course, results in a foreign key exception.
I can get around it by explicitly calling session.Flush() right after the Save(manager) call, but that doesn't seem very good practice.

any ideas?

Upvotes: 0

Views: 279

Answers (2)

Nadav the Gahbon
Nadav the Gahbon

Reputation: 31

The real problem is that your modeling is incorrect. In OO an object does not change its type. The Manager/Engineer should be modeled as One-To-One relationship. You can have a job class as a component property of Employee. Than when an employee is promoted from engineer to manager, you only have to replace the component. Also - you won't have to update the orders table, as the submitter remains the same. The only difference is its job component

Upvotes: 1

Jamie Ide
Jamie Ide

Reputation: 49261

As you stated, the problem is that ExecuteUpdate() occurs immediately and isn't issued after the new manager is inserted. I think that calling session.Flush() immediately is the right solution. You should also delete the original engineer object in the same transaction.

See also the answer to this question.

Upvotes: 0

Related Questions