Say I have an User entity and it haves a Password
property which is not nullable:
Map((x) => x.Password).Column("PASSWORD").Not.Nullable();
In the create action, I manually set the Password
value as it is a generated hash. It never goes to the View.
In the update, I try to save it, but I don't have the Password
value. I get this error for Password
propery:
PropertyValueException: not-null property references a null or transient value
This is my Update method:
public bool Update(UserViewModel input)
{
if (!IsValid(input))
return false;
var user = Mapper.Map<User>(input);
this.UserRepository.Update(user); // <- this is a wrapper for NH's Session.Update()
return true;
}
How can I tell NHibernate to ignore a property in an update?
Note: This is not the same as this question.
Update:
Here is how I use it: The Password
property never goes to any View. Even in the Login action I have a generic LoginViewModel
, only for it's view. That property is only used in the login process and it could be updated in the Reset password feature, where a new password is generated and sent to the related user e-mail.
I see 2 possibilities to achieve that
Get the entity before Update and update explicitly
// use 'Get()' because it uses the NHibernate cache
// if you already loaded the entity, it won't query the db and read it from the cache
var user = this.UserRepository.Get(input.Id);
user.PropertyToUpdate = ...;
this.UserRepository.Update(user);
In addition to that, you can use Dynamic-Update
. But this will only work with entities that are bound to the Session. NHibernate will then only update the changed properties and not all while you are updating a entity. Otherwise NHibernate can't know which properties has changed and will update all. DynamicUpdate should only work when you got the entity from NHibernate. The Entity is then bound to the Context and NHibernate can track changes.
If all your entities are auto mapped you can use a ClassConvention
to set DynamicUpdate to all your entities (or just filter the ones you want):
public class ClassConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.DynamicUpdate();
}
}
As another option you can use a explicit mapping override:
public class UserOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.DynamicUpdate();
}
}
Use different classes for different behaviours
You can declare different classes for the same Entity. One class for User creation or password resetting that contains the password property. And one class for simple updates that don't need the password property. FluentNhibernate allows you to map different classes for the same table. But you need a little more effort in mapping or rather in AutoMappingOverrides.