4 Replies - 332 Views - Last Post: 14 August 2017 - 06:49 AM

#1 andrewsw  Icon User is offline

  • lashings of ginger beer
  • member icon

Reputation: 6340
  • View blog
  • Posts: 25,569
  • Joined: 12-December 12

[CORE] Bind still sets values to NULL

Posted 14 August 2017 - 12:10 AM

The default Post scaffolding for editing a record with Entity Framework appears like this:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("Id,FirstName,LastName,Address,Salary")] MyModel myModel)
        {

That is, with all the fields listed in the BindAttribute.

I want the user to see all the data for the record, but only to be able to edit, say, the Address. So I modified the Bind attributed to show only Bind("Id,Address"). [I'm including Id for test purposes but it won't be changed.]

What happens is that, yes, it enables updating of the address, but all the other fields are reset to NULL.

Can someone explain this behaviour? How can I correct it please? Maybe there's an SQL update statement tucked away somewhere that I need to manually change?

Andy

Is This A Good Question/Topic? 0
  • +

Replies To: [CORE] Bind still sets values to NULL

#2 andrewsw  Icon User is offline

  • lashings of ginger beer
  • member icon

Reputation: 6340
  • View blog
  • Posts: 25,569
  • Joined: 12-December 12

Re: [CORE] Bind still sets values to NULL

Posted 14 August 2017 - 05:08 AM

Update: the only way I've found so far to get it to behave acceptably is to list ALL the fields:

public async Task<IActionResult> Edit(int id, [Bind("Id,FirstName,LastName,Address,Salary")] MyModel myModel)

then take manual charge of the modifications and updates with:

            if (ModelState.IsValid)
            {
                try
                {
                    _context.MyModel.Attach(myModel);    // instead of just Update()

                    _context.Entry(myModel).Property(x => x.Address).IsModified = true;


                    //_context.Update(myModel);
                    await _context.SaveChangesAsync();
                }

I still feel that this should be unnecessary. I should be able to show all the field-values, but only allow editing of certain of these fields.
Was This Post Helpful? 0
  • +
  • -

#3 andrewsw  Icon User is offline

  • lashings of ginger beer
  • member icon

Reputation: 6340
  • View blog
  • Posts: 25,569
  • Joined: 12-December 12

Re: [CORE] Bind still sets values to NULL

Posted 14 August 2017 - 05:18 AM

From this link:

Quote

That code is no longer recommended because the Bind attribute clears out any pre-existing data in fields not listed in the Include parameter.

That's a hellova detail to keep tucked away?!

Ah well, at least it explains what was going on, and is helping to point me in the right direction.
Was This Post Helpful? 0
  • +
  • -

#4 andrewsw  Icon User is offline

  • lashings of ginger beer
  • member icon

Reputation: 6340
  • View blog
  • Posts: 25,569
  • Joined: 12-December 12

Re: [CORE] Bind still sets values to NULL

Posted 14 August 2017 - 06:03 AM

I'll continue here and ask a related question.

Following from the MS link just above, I'm at this stage (having removed the Bind attribute completely):

                    if (await TryUpdateModelAsync<MyModel>(myModel, "", s => s.Address, s => s.ASecondField))
                    {
                        await _context.SaveChangesAsync();

                        return View(myModel);
                    }

[There is no TryUpdateModel as used in the linked page, nor can the field-names be directly supplied as a string array.]

It works. What happens is, the user edits the relevant fields and presses Save; it saves and reproduces the current page, which is fine.
If the user also modifies one of the other fields (by mistake or intention), the modification is ignored, which is good. However, after saving the record it is shown still with their invalid attempt to modify another field. If they move to the next record, and back, the correct details are shown - but not until they perform this navigation.

How can I show the correct representation of the current record's state? How can I discard their failed attempt to modify field(s) that they shouldn't be?

My current thought is to disable (in the HTML) all the un-modifiable fields, but I'm reluctant to modify all this HTML, and don't want the default greyed appearance.
Was This Post Helpful? 0
  • +
  • -

#5 andrewsw  Icon User is offline

  • lashings of ginger beer
  • member icon

Reputation: 6340
  • View blog
  • Posts: 25,569
  • Joined: 12-December 12

Re: [CORE] Bind still sets values to NULL

Posted 14 August 2017 - 06:49 AM

Right, the MS docs are wrong or, at least, outdated and misleading.

Consistent behaviour (although not yet tested exhaustively) is obtained with:

        _context.MyModel.Attach(myModel);

        _context.Entry(myModel).Property(x => x.Address).IsModified = true;
        _context.Entry(myModel).Property(x => x.AnotherProperty).IsModified = true;

        await _context.SaveChangesAsync();

        return RedirectToAction("Edit", id = id);

The TryUpdateModelAsync attempt either fails to submit the required changes or, at least, leaves the model in an inconsistent state. RedirectToAction also causes the (updated) record to be retrieved from the database.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1