views:

134

answers:

2

I do the following:

    var @case = new Case
    {
        Name = "test"
    };

    // User is persistent and loaded in the same session
    User.AddCase(@case); // sets @case.User = User too
    Session.Update(User);

    response.CaseId = @case.Id;

The cascade on User.Cases is set to All. But @case.Id is not set until the transaction is committed. Is that expected behavior? I would very much like to get the Id before committing. Can it be done?

A: 

have you tried Session.SaveOrUpdate(User)? Although i must say that cascaded operations do not take place until needed and that happens on flush/commit. when you Session.Save(@case) you are not flushing/commiting

Having said that you are making a logical mistake: by creating @case you are not updating the User. The user is a separate entity and Case has a foreign-key to User. So saving the Case is proper, and the List of cases a User is just association information

Jaguar
Sorry for the late reply to this answer. For some reason I have not seen the notification.
asgerhallas
Just to be clear, if I use Session.Save(@case) it would work, but I'm looking for a more pure DDD feel. So your answer that "cascaded operations do not take place until needed and that happens on flush/commit" is what makes this impossible.
asgerhallas
As for your last paragraph. From an OO point of view, you are not correct, and I want it to be as little relational as possible. From a RDBMS point of view you are correct, but that is why I use cascading: When I update the User, I want NH to update (or save) any Case in the collection too. I am taking care of the foreign-key reference in the AddCase method to abstract away the relational part. It works fine, except that the cascading is kicking in too late, thus I'm not getting IDs assigned before it's too late.
asgerhallas
+1  A: 

A more pure DDD'y feely thing would probably be to model both User and Case as aggregate roots and then model their relationship with a role object RelatedCase (that's aggregated inside User and thus should be cascade="all-delete-orphan").

Aggregate roots should be saved in repositories, which (if you delegate the call to session.Save(...)) will give you the id you need at a time where you can use it.

Then the role can (and in my experience often will, at least after some time) contain extra information that characterizes the relationship, and does not belong on neither on the user nor on the case. Let's say the relationship keeps track on why the user and the case are related.

This way your code could look like this:

var case = caseFactory.Create("name");
caseRepository.Save(case);

user.AssignCase(case, "Assigned by some dude");

-and inside AddCase:

public void AddCase(Case case, string reason)
{
    cases.Add(new RelatedCase(case, reason));
}

This is in my opinion the prettiest way to model this kind of thing, but you will of course be penalized a little bit performance-wise. If a pretty model is more important to you, then you should go for something like this.

mookid8000
Thanks! The above code, was mostly for the sake of the example. The real code does something more like: User.CreateCase(), and not much more. And the repository is of course not welcome in the domain classes. Modelled after this: http://www.udidahan.com/2009/06/29/dont-create-aggregate-roots/ . Your point about modelling the relation with a role object is very good. I'll look into that.
asgerhallas
But still. I may very well be on the wrong track, when this is not really supported :)
asgerhallas
Oh yeah, I was assuming you were inside an application service with access to injected services like a factory and a repository
mookid8000