1

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.

Community
  • 1
  • 1
DontVoteMeDown
  • 21,122
  • 10
  • 69
  • 105
  • Don't relevant to NHibernate but this post is about prevent a column from being updating in EF. It may have some useful notes for you. http://stackoverflow.com/questions/30777503/entity-framework-to-read-a-column-but-prevent-it-being-updated – Salah Akbari Mar 09 '17 at 15:03
  • @S.Akbari Thank you for the source. I want to find a non global way to do it and I'm afraid it is not possible, actually. – DontVoteMeDown Mar 09 '17 at 17:59
  • Do you use your Entity in the View? – Rabban Mar 10 '17 at 08:30
  • @Rabban check my update and see if it helps with your question. – DontVoteMeDown Mar 10 '17 at 11:08
  • 1
    This question is a more specialized case of this other [question](/q/1243390/1178314), with has well accepted answer. – Frédéric May 24 '17 at 11:42

1 Answers1

2

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.

Rabban
  • 2,451
  • 1
  • 19
  • 21
  • The first option is what I actually did to make it work, but it is not the best practice since it runs an additional query; The second option I don't think it will work for me. My app is big and all entities haves it own repositories and services(1 to 1) so spliting an entity into two different classes would break the default strutucture. I don't even thik if it would work actually; The third option we are already doing here. All mappings are set to `DynamicUpdate`. I'm afraid what I want to achieve isn't even possible, unfortunately. – DontVoteMeDown Mar 10 '17 at 12:12
  • @DontVoteMeDown Are your repositories just wrappers for the session or do they contain entity specific behaviour? – Rabban Mar 10 '17 at 12:16
  • They can contain specific behaviour. Linq queries we run in the service, but e.g. HQL, we only use in the repository layer. – DontVoteMeDown Mar 10 '17 at 12:20
  • The third option cannot work. It works only with entities loaded from the current session. So that boils down to using the first option, but avoiding an "update with read value" on password, on top of it. I think it would be better you reword your third point as a potential improvement to the first point. (It is already near to be that after all.) – Frédéric May 24 '17 at 10:14
  • @Frédéric you are right. I totally forget that i already provided an answer to such a question. I removed point 3 and added it to point 1 to make it more clear. thanks for the suggestion. – Rabban May 24 '17 at 10:43