-1

am having a weird functionality when am only updating other fields other than the image , the other fields (FirstName , LastName) update successfully but then the Image sets its self to null, but when I choose it with respect to other fields (FirstName, LastName) it updates successfully. So what I want is when I don't update the image it stays as it is without setting its self to null.

This is my New.cshtm file which handles both Creating and Editing data :

<form asp-action="New" method="Post" asp-controller="Student" enctype="multipart/form-data">
    <div asp-validation-summary="All"></div>

    <input asp-for="Id" type="hidden"/>
    <input name="IsEditMode" id="IsEditMode" value="@ViewBag.IsEditMode" type="hidden"/>


    <div class="form-row">
        <label>Upload Photo</label>
        <input asp-for="ImageUrl" type="file" id="file"  name="file" class="form-control"/>

    </div>

    <div class="form-row">
        <div class="col">
            <label asp-for="FirstName"></label>
            <input asp-for="FirstName" class="form-control"/>
            <span asp-validation-for="FirstName" class="text-danger"></span>
        </div>
        <div class="col">
            <label asp-for="MiddleName"></label>
            <input asp-for="MiddleName" class="form-control"/>
            <span asp-validation-for="MiddleName" class="text-danger"></span>
        </div>
    </div>
</form>

Then these are the methods of my controller Student.cs am using to update the fields :

public IActionResult New(Student student, string IsEditMode, IFormFile file)
        {

            if (!ModelState.IsValid)
            {
                ViewBag.IsEditMode = IsEditMode;
                return View(student);
            }

            try
            {

                if (IsEditMode.Equals("false"))
                {

                    _studentRepository.Create(student);
                     UploadFile(file, student.Id);
                    _toastNotification.AddSuccessToastMessage("Student has been created successfully.");

                }

                else
                {
                    _studentRepository.Edit(student);
                     UploadFile(file, student.Id);
                    _toastNotification.AddSuccessToastMessage("Student has been edited successfully.");

                }

                return RedirectToAction(nameof(Index));
            }
            catch (Exception e)
            {

                return RedirectToAction(nameof(Index));
            }

        }

        public IActionResult Edit(int id)
        {

            try
            {

                ViewBag.IsEditMode = "true";

                var student = _studentRepository.GetSingleStudent(id);

                return View("New", student);
            }
            catch (Exception ex)
            {
                return Content("Could not find Pet");
            }

        }

        public void UploadFile(IFormFile file, long studentId)
        {
            var fileName = file.FileName;
            var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/images",fileName);

            using (var fileStream = new FileStream(path, FileMode.Create))
            {
                file.CopyTo(fileStream);
            }

            var student = _studentRepository.GetSingleStudent(studentId);
            student.ImageUrl = fileName;
            _studentRepository.Edit(student);
        }

Then, this is how I am Updating in the Repository :

Then in my Repository, this is how I am updating the fields " :

public void Edit(Student student)
        {
            var existingStudent = _context.Students

                .FirstOrDefault(s => s.Id == student.Id);

            if (existingStudent != null)
            {
                // updating student.

                _context.Entry(existingStudent).CurrentValues.SetValues(student);
                _context.Entry(existingStudent).State = EntityState.Modified;
          }
}

The Index.cshtml, this is one list the images and the First and LastName and the (action buttons) Edit, Delete buttons :

<table class="table table-striped">
        <thead class="thead-dark">
        <tr>
            <td ><b>Student Picture</b></td>
            <td><b>FirstName</b></td>
            <td><b>LastName</b></td>
            <td colspan="2"> <b>Actions</b></td>
        </tr>
        </thead>
        <tbody>
        @foreach (var student in Model)
        {
            <tr>
                <td>@student.StudentRegNo</td>
                <td>
                    <div class="thumbnail">
                        <img src="/images/@student.ImageUrl" width="90" height="90"/>
                    </div>
                </td>
                <td>@student.FirstName</td>
                <td>@student.LastName</td>
                <d>
                    <td>
                        <a class="btn btn-warning" asp-action="Details" asp-controller="Student" asp-route-Id="@student.Id">Details</a>
                    </td>
                    <td>
                        <a class="btn btn-primary" asp-action="edit" asp-route-Id="@student.Id">Edit</a>
                    </td>
                    <td>
                        <a
                            class="btn btn-danger delete"
                            asp-route-Id="@student.Id"
                            asp-action="Delete">
                            Delete
                        </a>
                    </td>
                </d>
            </tr>
        }
        </tbody>
    </table>

EDIT

This is the current logic am having according to @Raul solution, but it's not working :

if (student.ImageUrl != null)
                {
                    _context.Entry(existingStudent).CurrentValues.SetValues(student);
                    _context.Entry(existingStudent).State = EntityState.Modified;
                }

                else
                {
                    _context.Entry(existingStudent).Property(x => x.ImageUrl).IsModified = false; 
                    _context.Entry(existingStudent).CurrentValues.SetValues(student);
                    _context.Entry(existingStudent).State = EntityState.Modified;
                }

Idris Stack
  • 546
  • 1
  • 14
  • 36
  • 1
    You can check if your image received during your update is `null` and if it is then you can `attach` your model like: `_context.Entry.Attach(existingStudent);` and then set the modified field to false for your `ImageUrl`: `_context.Entry(existingStudent).State = EntityState.Modified; _context.Entry(existingStudent).Property(x => x.ImageUrl).IsModified = false; _context.SaveChanges();` – Rahul Sharma Jul 17 '19 at 13:02
  • Hey @RahulSharma, am actually trying to get your point, but would you kindly include this as an answer with an edit of my `void Edit(Student student)` , I will be very grateful thanks. – Idris Stack Jul 17 '19 at 13:19
  • 1
    Looks like you deleted your previous question and posted it anew. Don't do that. Regardless, the answer is the same: *stop using `CurrentValues.SetValues`*. You already had your answer, you're just stubbornly refusing to accept it. – Chris Pratt Jul 17 '19 at 13:22

2 Answers2

1

In your Edit student method, you can set the IsModified to false for your ImageUrl Property which will not update the image field in your database:

public void Edit(Student student)
{
  var existingStudent = _context.Students.FirstOrDefault(s => s.Id == student.Id);

  if (existingStudent != null)
  {
    // updating student.
    _context.Student.Attach(existingStudent);
    _context.Entry(existingStudent).State = EntityState.Modified; 
    _context.Entry(existingStudent).Property(x => x.ImageUrl).IsModified=false; 
    _context.SaveChanges();
  }
}

Of course, you would need to check for your ImageUrl logic in this. If you get a new image then you update your model accordingly.

EDIT:

You can incorporate your if-else condidition like this:

if (student.ImageUrl != null)
{              
 _context.Student.Add(existingStudent);
 _context.Entry(existingStudent).State EntityState.Modified;
 //_context.Student.Update(existingStudent); //You can also use this. Comment out the upper two lines
 _context.SaveChanges();
}
else
{
    // updating student.
    _context.Student.Attach(existingStudent);
    _context.Entry(existingStudent).State = EntityState.Modified; 
    _context.Entry(existingStudent).Property(x => x.ImageUrl).IsModified=false; 
    _context.SaveChanges();
}
Rahul Sharma
  • 7,768
  • 2
  • 28
  • 54
  • Hey Raul sorry for the late response, when I implemented your solution it works but the thing is there are ***two scenarios***, 1. Updating fields without updating the image. 2. Updating the fields and the image. Now the for scenario *1* your solution works but it doesn't work for *2*. I tried to come up with a logic but didn't work. Let me share my logic here. maybe the last thing, this line `_context.Entry.Attach(existingStudent);` , `Attach` is not resolved. I will be very grateful with your response. – Idris Stack Jul 17 '19 at 19:23
  • For the second scenario, you can use .Update method with your existingStudent model. – Rahul Sharma Jul 17 '19 at 19:25
  • Hey Raul, I have updated my question, check at the bottom there's an *EDIT* section where my current code is. Thanks. – Idris Stack Jul 17 '19 at 19:26
  • Hey Raul , when I use the `Update()` like so `_context.Update(student);`, still the same thing. In the `If`section. – Idris Stack Jul 17 '19 at 19:31
  • Hey Raul I think I made some mistake while explaining in my first comment on this line (**Now the for scenario *1* your solution works but it doesn't work for 2. I tried to come up with a logic but didn't work**), actually, your solution works on scenario *2* but on *1* it doesn't work because this is where the image is set to `null` – Idris Stack Jul 17 '19 at 19:36
  • `Update` is not resloved on this line `_context.Entry(existingStudent).Update(setting);` – Idris Stack Jul 17 '19 at 19:42
  • `Update` and `AddOrUpdate` are not part of `Entry` – Idris Stack Jul 17 '19 at 20:27
  • @Raul, Entry is not my class it's for EF , that's why `Add` is also not part as `Update` and `AddOrUpdate`. `Student` is the model class am using. – Idris Stack Jul 17 '19 at 20:55
  • Let me implement it. – Idris Stack Jul 17 '19 at 21:16
1

You could consider the two scenario separately.When updating fields without updating the image, the file is null, then you need to assgin the ImageUrl of existing student to the posted student.

        //...
        try
        {
            if (IsEditMode.Equals("false"))
            {
                _studentRepository.Create(student);
                UploadFile(file, student.Id);
                _toastNotification.AddSuccessToastMessage("Student has been created successfully.");

            }
            else
            {
                //edit mode
                if(file == null)//Updating fields without updating the image.
                {
                    var existingStudent = _context.Students.FirstOrDefault(s => s.Id == student.Id);

                    if (existingStudent != null)
                    {
                        // updating student with previousImageUrl
                        student.ImageUrl = existingStudent.ImageUrl;
                        _context.Entry(existingStudent).CurrentValues.SetValues(student);
                        _context.Entry(existingStudent).State = EntityState.Modified;
                        _context.SaveChanges();
                    }
                }
                else//Updating the fields and the image
                {
                    _studentRepository.Edit(student);
                    UploadFile(file, student.Id);
                }

                _toastNotification.AddSuccessToastMessage("Student has been edited successfully.");

            }

            return RedirectToAction(nameof(Index));
        }
        catch (Exception e)
        {
            return RedirectToAction(nameof(Index));
        }
    }

    public void UploadFile(IFormFile file, long studentId)
    {
        var fileName = file.FileName;
        var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/images", fileName);

        using (var fileStream = new FileStream(path, FileMode.Create))
        {
            file.CopyTo(fileStream);
        }

        var student = _studentRepository.GetSingleStudent(studentId);
        student.ImageUrl = fileName;
        _studentRepository.Edit(student);
    }

   public void Edit(Student student)
    {
        var existingStudent = _context.Students

            .FirstOrDefault(s => s.Id == student.Id);

        if (existingStudent != null)
        {
            // updating student.

            _context.Entry(existingStudent).CurrentValues.SetValues(student);
            _context.Entry(existingStudent).State = EntityState.Modified;
            _context.SaveChanges();
       }
    }
Ryan
  • 19,118
  • 10
  • 37
  • 53