1

I have method Edit that uploads one image for Main Page and multiple images for gallery to the existing record in database. I have one to many relationship table (FurnitureImages where I store info about image) , also I use View Model So here my code

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(FurnitureVM model)
{
    if (model.MainFile != null && model.MainFile.ContentLength > 0)
    {
        string displayName = model.MainFile.FileName;
        string extension = Path.GetExtension(displayName);
        string fileName = string.Format("{0}{1}", Guid.NewGuid(), extension);
        string path = "~/Upload/" + fileName;
        model.MainFile.SaveAs(Server.MapPath( path));
        model.MainImage = new ImageVM() { Path = path, DisplayName = displayName };
    }     
    foreach (HttpPostedFileBase file in model.SecondaryFiles)
    {
        FurnitureImages images = new FurnitureImages();
        if (file != null && file.ContentLength > 0)
        {
            string displayName = file.FileName;
            string extension = Path.GetExtension(displayName);
            string fileName = string.Format("{0}{1}", Guid.NewGuid(), extension);
            var path = "~/Upload/" + fileName;
            file.SaveAs(Server.MapPath(path));
            model.SecondaryImages = new List<ImageVM> { new ImageVM { DisplayName = displayName, Path = path } };
        }
    }
    if (!ModelState.IsValid)
    {
        model.CategoryList = new SelectList(db.Categories, "CategoryId", "Name",model.CategoryId); // repopulate the SelectList
        return View(model);
    }

    Furniture furniture = db.Furnitures.Where(x => x.FurnitureId == model.ID).FirstOrDefault();
    FurnitureImages main = furniture.Images.Where(x => x.IsMainImage).FirstOrDefault();
    furniture.Name = model.Name;
    furniture.Description = model.Description;
    furniture.Manufacturer = model.Manufacturer;
    furniture.Price = model.Price;
    furniture.CategoryId = model.CategoryId;
    furniture.Size = model.Size;       
    main.DisplayName = model.MainImage.DisplayName;
    main.Path = model.MainImage.Path;
    main.IsMainImage = model.MainImage.IsMainImage;
    if (model.MainImage != null && !model.MainImage.Id.HasValue)
    {
        FurnitureImages image = new FurnitureImages
        {
            Path = model.MainImage.Path,
            DisplayName = model.MainImage.DisplayName,
            IsMainImage = true
        };
        furniture.Images.Add(image);
        db.Entry(furniture).State = EntityState.Modified;
    } 
    // Update secondary images
    IEnumerable<ImageVM> newImages = model.SecondaryImages.Where(x => x.Id == null);
    foreach (ImageVM image in newImages)
    {
        FurnitureImages images = new FurnitureImages
        {
            DisplayName = image.DisplayName,
            Path =  image.Path , 
            IsMainImage = false
        };
        furniture.Images.Add(images);
    }
    ViewBag.CategoryId = new SelectList(db.Categories, "CategoryId", "Name", furniture.CategoryId);
    db.SaveChanges();
    return RedirectToAction("Index");
}

Main image uploads good , but when I try to upload multiple images from another input file

@Html.TextBoxFor(m => m.SecondaryFiles, new { type = "file", multiple = "multiple" , name = "SecondaryFiles" })
@Html.ValidationMessageFor(m => m.SecondaryFiles)
@for (int i = 0; i < Model.SecondaryImages.Count; i++)
{
    @Html.HiddenFor(m => m.SecondaryImages[i].Id)
    @Html.HiddenFor(m => m.SecondaryImages[i].Path)
    @Html.HiddenFor(m => m.SecondaryImages[i].DisplayName)
    <img src="@Url.Content(Model.SecondaryImages[i].Path)" />
}

It uploads only one image , And as much as I keep trying to upload many images, it always upload only one, so where are errors in my method?

10
  • Call db.Entry(furniture).State = EntityState.Modified; immediately before db.SaveChanges(); Commented Feb 25, 2017 at 23:24
  • @StephenMuecke i tried it , something wrong , uploads only 1 image , when I select 2 or more Commented Feb 25, 2017 at 23:38
  • Do you mean it uploads only one of the SecondaryImages when you select more that one? (and are you referring to uploading (saving the file to disk) or saving the item to the database in the FurnitureImages table?) Commented Feb 25, 2017 at 23:46
  • You have a few other issues with your code - but what your referring to is caused by your model.SecondaryImages = new List<ImageVM> { new ImageVM { DisplayName = displayName, Path = path } }; - you keep overwriting the collection. It needs to be model.SecondaryImages.Add(new ImageVM { ... }) inside the loop Commented Feb 25, 2017 at 23:48
  • @StephenMuecke yes , I mean it uploads only one of the SecondaryImages when I select more that one . In my logic when I upload image it uploads to the folder in file system and info about image creates and store in database , I tried to add EntityState.Added but I get an error Commented Feb 25, 2017 at 23:49

1 Answer 1

1

Your issue is that inside the first foreach loop, you correctly save each file to the server, but in each iteration, your creating an new List<ImageVM> and overwriting the value of SecondaryImages so when the loop has completed, it contains only one item (based on the last image).

Change the loop to

foreach (HttpPostedFileBase file in model.SecondaryFiles)
{
    // FurnitureImages images = new FurnitureImages(); -- DELETE
    if (file != null && file.ContentLength > 0)
    {
        string displayName = file.FileName;
        string extension = Path.GetExtension(displayName);
        string fileName = string.Format("{0}{1}", Guid.NewGuid(), extension);
        var path = "~/Upload/" + fileName;
        file.SaveAs(Server.MapPath(path));
        // Add a new ImageVM to the collection 
        model.SecondaryImages.Add(new ImageVM { DisplayName = displayName, Path = path });
    }
}

Note that the above assumes you view model has a parameter-less constructor that initializes SecondaryImages. If not, then add model.SecondaryImages = new List<ImageVM> before the loop.

A few other minor issues to address.

  1. The code for generating the SelectList should be just model.CategoryList = new SelectList(db.Categories, "CategoryId", "Name"); - the last parameter of the SelectList constructor is ignored when binding to a model property so its pointless.
  2. Delete the ViewBag.CategoryId = new SelectList(...) line of code. Your model already contains a property for the SelectList (as per note 1) but in any case, your redirecting, so adding anything to ViewBag is pointless.
  3. Move your db.Entry(furniture).State = EntityState.Modified; line of code to immediately before db.SaveChanges();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.