Skip property on update in NHibernate

2019-07-26 20:24发布

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.

1条回答
别忘想泡老子
2楼-- · 2019-07-26 20:59

I see 2 possibilities to achieve that

  1. 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();
        }
    }
    
  2. 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.

查看更多
登录 后发表回答