views:

144

answers:

3

Hi,

I am using Fluent NHibernate to do my NHibernate mappings, but now I have come to a problem that I am not sure how to solve. A simplified version of the problem follows.

I have a user class:

public class User {
    public virtual int Id { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
}

This is the associated Fluent NHibernate Class Map

public class UserMap : ClassMap<User> {
    public UserMap() {
        Id(x => x.Id);
        Map(x => x.FirstName);
        Map(x => x.LastName);
 }
}

I have two web forms. One form allows me to change the users first name, and the second form allows me to change the users last name. What I am trying to achieve is a simple SQL statement like this:

For the first form:
UPDATE [users] SET firstname='new first name' WHERE id=1

For the second form:
UPDATE [users] SET lastname='new last name' WHERE id=1

Currently NHibernate performs the following SQL on my database:
UPDATE [users] SET firstname=null, lastname='new last name' WHERE id=1

The problem in the real world application, is that there are too many properties to update on some big objects (as well as access restrictions), and it seems pointless to update the whole object, when all I want / am allowed to do is update a single property.

I am hoping that someone can provide some advice as to how I can realise this, or point me in the right direction to solve this.

Thanks in advance, Dai

A: 

Hibernate's doing the right thing, but your problem indicates that your schema needs some normalization.

McWafflestix
Thanks for comment Mcwafflestix. I am not sure that I have put the question correctly, just to confirm that I am not too concerned with normalization, in my case it is a performance trade off by design. De-normalization does have many advantages when used correctly. ;-). Apart from the "normalization" issues, could you suggest any possible remedies optimizing the NHibernate Queries?
Dai Bok
Generally, I'd still suggest normalization. Here's the thing; you're right, that de-normalized tables can have many advantages, but one of the disadvatages of using them is that it can be hard to customize out-of-the-box solutions (such as Hibernate) for them. I'd suggest you need to weigh your tradeoffs; is it more important to maintain your denormalized database (and need to customize Hibernate's table accesses) than it is to normalize your schema (and be able to use Hibernate "as is")? Only you can make that decision; I'd side on the "normalize" end of things.
McWafflestix
A: 

See this: http://stackoverflow.com/questions/813240/nhibernate-update-on-single-property-updates-all-properties-in-sql

queen3
thanks Queen3, I am reading through some things now, and I looks like most ORMs update all object fields, even if only one field is gets dirty. I will Look into this problem a bit more, I am thinking of alternative approaches now, using stored procedures, or old fashioned ADO.net :-)
Dai Bok
See here for more discussions: http://stackoverflow.com/questions/1243390/what-is-the-best-approach-to-update-only-changed-properties-in-nhibernate-when-se. Also, I don't really understand why you are going to trade simplicity and do lots of manual works right away - have you tried the solution? Won't dynamic-update work for you (mapping.DynamicUpdate() in FNH)?
queen3
I have just double checked my code. I have exported the FNH mappings, and they have Dynamic Updates enabled, but this does not seem to make any difference. Just rewriting my repository so I can use the same session and see if select before update makes a difference.
Dai Bok
Thanks for your help Queen3, can not vote your answer up, still a noob!
Dai Bok
A: 

Ok, that works, Thanks for the help and tips Queen3!

here is how I sovled it:

using (var sf = Repository.CreateSessionFactory()) { 
    using (var s = sf.OpenSession()) { 
        using (var t = session.BeginTransaction()) { 
            var existingUser = s.Get<User>(editedUser.Id); 
            existingUser.LastName = editedUser.LastName; 
            s.SaveOrUpdate(existingUser); 
            t.Commit(); 
        }
    } 
}

Although this does work, it requires that I retrieve the User from the database first and work within the same session. The good thing is that the sql statement that is generated just updates the dirty LastName field. :-)

I am unable to get it to work with a detached instance of the user, this is similar to how I was doing it before, which resulted in every field of the user being updated.

using (var sf = Repository.CreateSessionFactory()) { 
    using (var s = sf.OpenSession()) { 
        using (var t = session.BeginTransaction()) { 
            s.SaveOrUpdate(editedUser); 
            t.Commit(); 
        }
    } 
}
Dai Bok