Sam
Sam

Reputation: 10113

NHibernate Issuing Additional UPDATE on Unidirectional One-to-Many

I'm using the new Map by Code pieces in NHibernate. My understanding was that an update was made in NHibernate 3 so that unidirectional one-to-many relationships would no longer insert null on the foreign key then update it to the correct value, as long as you set inverse=false on the collection and made the foreign key not nullable.

What I'm seeing is that NHibernate now INSERTs the correct foreign key, but it still issues an additional UPDATE that sets the foreign key to the value that was used in the insert?!?

Have I done something incorrectly in my mapping? (A user can have many passwords. The password object does not reference back to the user in my domain.)

mapper.Class<Password>(map =>
{
    map.Table("Passwords");
    map.Id(x => x.Id, x => { x.Generator(Generators.Native); x.Column("PasswordId"); });
    map.Property(x => x.PasswordFormat, x => { x.NotNullable(true); });
    map.Property(x => x.Salt, x => { x.Length(100); });
    map.Property(x => x.PasswordValue, x => { x.NotNullable(true); x.Length(500); });
    map.Property(x => x.CreateDate, x => { x.NotNullable(true); });
});

mapper.Class<User>(map =>
{
    map.Table("Users");
    map.Id(x => x.Id, x => { x.Generator(Generators.Native); x.Column("UserId"); });
    map.Property(x => x.UserName, x => { x.NotNullable(true); x.Length(100); x.UniqueKey("UX_Users_Username"); });
    map.Property(x => x.Email, x => { x.Length(100); x.Index("IX_Users_Email"); });
    map.Property(x => x.IsAnonymous, x => { x.NotNullable(true); });
    map.Property(x => x.IsApproved, x => { x.NotNullable(true); });
    map.Property(x => x.LastActivityDate, x => { x.NotNullable(true); });
    map.Property(x => x.CreateDate, x => { x.NotNullable(true); });
    map.Set(x => x.Passwords, x => { x.Access(Accessor.Field); x.Inverse(false); x.Key(k => { k.Column("UserId"); k.NotNullable(true); k.ForeignKey("FK_Passwords_UserId"); }); x.Cascade(Cascade.All); x.Lazy(CollectionLazy.Lazy); }, x => x.OneToMany());
});

Note: This is using built-in NHibernate.Mapping.ByCode, not Fluent NHibernate.

Upvotes: 3

Views: 777

Answers (2)

Sam
Sam

Reputation: 10113

Turns out I can accomplish this by setting k.Update(false) on the foreign key portion of the Passwords collection mapping.

The answer from hazzik on the following question queued me in.

https://stackoverflow.com/a/11576097/139694

Upvotes: 2

Sunny
Sunny

Reputation: 4809

It should be Inverse() not Inverse(false).

Inverse() means that other entity owns the relationship and it is responsible for providing data for NHibernate about the relationship while inserting/updating information i.e., if "user" is set to on inverse, "password" needs to take care of providing relationship info. to NHibernate.

For this you need to set up "User" reference property on "Password" entity. And while creating/updating the password, assign user property explicitly.

//create new password
Password objPassword = new Password();
objPassword.otherproperties =///assign
objPassword.User = <<---assign the user property

Currently, you have Inverse(false) which is default setting for NHibernate. In this case, insert statements will be executed with passwordid as null and then references are updated resulting in two operations.

Upvotes: 1

Related Questions