views:

134

answers:

2

Hi

I have a complex entity User:

    public class User : BaseEntity
    {        
    public virtual Taxi Taxi { get; set; }  --> That is why i call it "complex"
    public virtual string Login { get; set; }           
    public virtual string Password { get; set; }  
    }

where Taxi is a parent of User (Taxi has-many Users):

    public class Taxi : BaseEntity
    {
      public virtual string Name { get;  set; }
      public virtual string ClientIp { get;  set; }
    }

BaseEntity consists of public virtual int Id { get; private set; }

The problem occurs while trying to edit User

    [Authorize]  
    public ActionResult ChangeAccountInfo()
    {
        var user = UserRepository.GetUser(User.Identity.Name);
        return View(user); 
    }

My ChangeAccountInfo.aspx

        <fieldset>
        <legend>Fields</legend>
        <%  %>
        <div class="editor-label">
            <%: Html.LabelFor(model => model.Login) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Login) %>
            <%: Html.ValidationMessageFor(model => model.Login) %>      
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Password) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Password) %>
            <%: Html.ValidationMessageFor(model => model.Password) %>
        </div>  

         <div class="editor-field">
            <%: Html.HiddenFor(model => model.Taxi.Name)%>               
        </div>     

        <p>
            <input type="submit" value="Save" />
        </p>
       </fieldset>

Post changes:

    [Authorize]
    [HttpPost]
    public ActionResult ChangeAccountInfo(User model)
    {
        if (ModelState.IsValid)
        {
            UserRepository.UpdateUser(model); 

            return RedirectToAction("ChangeAccountInfoSuccess", "Account");
        }

        return View(model);
    }

But, the (User model) parameter has User.Id == 0 --> User entity had 5 before edit
User.Login == "my new login"
User.Password == "my new password"
User.Taxi.Id == 0 --> User.Taxi entity had 3 before edit
User.Taxi.Name == "old hidden name"
User.Taxi.ClientIp == null --> User entity had 192.168.0.1 before edit

Q: Is it possible not to mark all the fields of an entity (that should be in my UpdateUser) with tag "hidden" but still have them unchanged in my HttpPost method? e.g. not User.Taxi.ClientIp = null, but User.Taxi.ClientIp = 192.168.0.1

I'm using nhibernate, if it matters.

+1  A: 

Not without some heavy lifting. I'm not sure if nhibernate cares that it is the same exact instance or not; you might only have to keep the entity's ID for your form to work.

If the second case is true, all you need to do is create a hidden field in your form to store the id of the model. MVC will do the rest. Just chuck this in your form at the top:

<%= Html.HiddenFor(model => model.Id) %>

You can specify (via a whitelist or a blacklist) what properties can/cannot be edited within the form, if you're concerned about people hacking (and you should be).

Will
I thought there is some way to get instance of entity after editing with only few editable fields changed, and all other readonly fields keep their old values. I'm newbie in asp mvc the same as in nhibernate, so i still need to check whether it is sufficient for nhibernate to specify only User.Taxi.Id to have the right reference between User and Taxi and not to cause invalid update of Taxi.
jjjjj
@jjj you have to realize that ASP.NET MVC (and the web in general) is stateless. Apart from a few exceptions, everything goes away inbetween calls from the client to the server. So unless you use some kind of storage mechanism to "hold on" to a reference to the model instance between calls (however long that is), it will be disposed of and collected by the system as soon as your controller method exits. The cheap and dirty method is to stick the User be stored in the Session. The better solution is the one I provided, imho. There are other ways, depending on ur requirements as well...
Will
Yeah,i don't need User object in my http Session for this long. Now i got stuck with my Id property which is private for all my entities(common solution for apps using nhib), so Html.HiddenFor(model => model.Id) returns 0 for Id. Even making it public doesn't solve the problem, it still not updating User 'cause of unfilled notnull fields in User.Taxi. The way i see now is to to get oldUser by id in my httpPost method, update it manually with received(posted) instance of newUser, and then save oldUser with changes.I understood your explanation about web,thanks,the issue now is in nhibernate
jjjjj
@jjj Sorry, can't help you with nhib specifically. You might try to grab the current version of your User from the repository then use the Try/UpdateModel methods to update your user.
Will
A: 

The answer suggested by Will is the best matching my issue:
To Edit your entity
- Provide your View with entity identity that you want to edit
- Post your model with identity in hidden field (in my case i can't use model.Id private setter because of nhib mapping settings)
- In httpPost method use GetById(idFromHiddenField) to retrieve your entityFromDatabase
- use UpdateModel(entityFromDatabase) - that will merge old version(entityFromDatabase) and new version of entity
- Then ISession.Update(entityFromDatabase) to persist changes into database

jjjjj