tags:

views:

417

answers:

4

I have situation where a Message table has a primary key (Id) and a foreign key (Site). Any site can create a message record, but only the site that created the record can update it. The problem is that by default it will be updated based upon Id and not Id and Site. I could change the primary key to be a composite/compound id consisting of the id and site OR resort to Native SQL; however, I was wondering if there is a way to add additional Update criteria.

For example, this is what you get by default:

public void MessageUpdate(Message oneMessage)
{
    using(ISession session = SessionFactory.OpenSession())
    using(ITransaction trans = session.BeginTransaction())
    {
        session.Update(oneMessage);
        trans.Commit();
    }
}

So how do I do this in NHibernate without creating a compound id or using Native SQL:

Update MessageTable set MessageStatus = 2 where Id = ? and Site = ?;
A: 

What I understand of your question the rule is a business requirement, so maybe NHibernate is not the place to this rule. You can try to implement a listener on the update event : http://nhforge.org/blogs/nhibernate/archive/2009/04/29/nhibernate-ipreupdateeventlistener-amp-ipreinserteventlistener.aspx

An other solution is to mark the property with update to false to prevent the change of the record's site ? http://nhforge.org/doc/nh/en/index.html#mapping-generated (see generated property)

Matthieu
The security rule would be, "Users cannot update message records for sites that they do not have access to". If a user logon is compromised, the attacker can only mess up messages associated with a given site. If I can had additional update criteria, I could take the incoming ID and status from the user and get their Site id from the database. I can then build an update statement using id, siteid and status. Thus, a user that does not have access to a site could never mess up another site's records.
David Yates
A: 

You can't do it directly in NHibernate but you could alter your update method to:

public void MessageUpdate(Message oneMessage, string currentSite)
{
    if (oneMessage.Site != currentSite)
    {
        throw new Exception("meaningful error message");
    }
    using(ISession session = SessionFactory.OpenSession())
    using(ITransaction trans = session.BeginTransaction())
    {
        session.Update(oneMessage);
        trans.Commit();
    }
}

Assuming Site is a string and a property of Message. Also, you will want to wrap your update in a try..catch and rollback the transaction if an exception occurs.

Jamie Ide
David Yates
Jamie Ide
Jamie, thanks for your response. I guess the short answer to my original question is that you cannot add criteria to an update.In your example I would still have to query for the original message in the database, update the status field, leave the site id alone, and then call your MessageUpdate method with the message and current site that the user is allowed to access.This will certainly work, but using native sql I can avoid the query and use a where statement to verify that the users site id matches the site id in the record. If no records are updated, I can take various actions.
David Yates
A: 

I guess the short answer to my original question is that you cannot add criteria to an update. You can use native SQL to handle this situation as I originally suggested:

Update MessageTable set MessageStatus = 2 where Id = ? and Site = ?;

Or you could approach the problem as Jamie Ide suggested, but it will require an additional query against the database to pull the original message.

David Yates
A: 

I have the same problem and there's no answer for that.

I'm looking resolution for creating overlapped events in my calendar application. Events can be created very quickly by webservice and I have no control over overlapped events but I want to avoid that situation.

If I could set Criteria to Update query then I will be able to avoid overlapping.

dario-g