ricky89
ricky89

Reputation: 1396

Create Item and add images for Item in one step

I am trying to learn ASP.net by making an e-commerce site. I am trying to set up the ability to create Items and assign Images to the item being created via File Upload.

I managed to get the multiple file upload working, but only to the content/Images folder. I cant figure out out to marry this to the creation of Items so you can assign multiple images to an Item all in the creation of the item.

It would be a fair to say I dont know where to go from here and would appreciate any help.

Item Model Class: Table in the database to store each item. Is referenced from the Images Table with a 1 to many relationship.

 public class Item
 {
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ItemId { get; set; }
    public int CategoryId { get; set; }
    public int DesignerId { get; set; }
    public int ImageId { get; set; }
    [Required]
    [MaxLength(250)]
    public string ItemName { get; set; }
    [Required]
    [Range(0,9999)]
    public decimal ItemPrice { get; set; }
    [MaxLength(1000)]
    public string ItemDescription { get; set; }
    [Range(4,22)]
    public int ItemSize { get; set; }

    [Column("CategoryId")]
    public virtual List<Category> Category { get; set; }
    public virtual List<OrderDetail> OrderDetails { get; set; }
    public virtual List<Image> Images { get; set; }
}

Image Model Class: Stores the URL for each Image in the content Directory of the site. Can have many images for each Item.

public class Image
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ImageId { get; set; }
    [Required]
    public string ImageURL { get; set; }
    [Required]
    public string ItemId { get; set; }

    //Files Being Uploaded by the User
    public IEnumerable<HttpPostedFileBase> Files { get; set; }

    [Column("ItemId")]
    public virtual List<Item> Item { get; set; }
}

Store Manager Controller

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Item item,HttpPostedFileBase file)
    {
        if (ModelState.IsValid)
        {

            //The below successfully saves the file to the content folder when separated into the Index Action.
            foreach (var f in item.Files)
            {
                if (file.ContentLength > 0)
                {
                    var fileName = Path.GetFileName(f.FileName);
                    var path =   Path.Combine(Server.MapPath("~/Content/ItemImages/"+item), fileName);
                    file.SaveAs(path);
                }
            }

    // The below also works when I dont have the Above in the Action.
            db.Items.Add(item);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(item);
    }

Create Item View

    @model Project.Models.Item

    @{
       ViewBag.Title = "Create";
     }

    <h2>Create</h2>

    @using (Html.BeginForm()) {
       @Html.AntiForgeryToken()
       @Html.ValidationSummary(true)

    <fieldset>
        <legend>Item</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.ItemName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ItemName)
            @Html.ValidationMessageFor(model => model.ItemName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ItemPrice)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ItemPrice)
            @Html.ValidationMessageFor(model => model.ItemPrice)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ItemDescription)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ItemDescription)
            @Html.ValidationMessageFor(model => model.ItemDescription)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ItemColour)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ItemColour)
            @Html.ValidationMessageFor(model => model.ItemColour)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ItemSize)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ItemSize)
            @Html.ValidationMessageFor(model => model.ItemSize)
        </div>

        <p>
           <input type="submit" value="Create" />
        </p>
</fieldset>
}

    @using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        <div>
        <table>
            <tr>
                <td>Files</td>
                <td><input type="file" name="Files" id="Files" multiple/></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" name="submit" value="Upload" /></td>
            </tr>
        </table>
        </div> 
    }

   <div>
       @Html.ActionLink("Back to List", "Index")
   </div>

Upvotes: 0

Views: 99

Answers (1)

Kyle Gobel
Kyle Gobel

Reputation: 5750

So it looks like you're pretty close.

You just have to add the images to the item before adding it to the database.

Since you're using EF, it should be something similar to this

 //in your action

 //add the images to the item
 item.Images.Add(new Image { ImageUrl = ... });

 //you should be able to just insert the whole entity graph here
 db.Items.Add(item);
 db.SaveChanges();

Something like that I think is what you're looking for.

Also in your model constructor normally I think you want to initalize those lists so you don't get null reference execeptions when doing something like the above

public class Item 
{
    public Item()
    {
        this.Images = new List<Image>();
    }
    //...
}

Upvotes: 1

Related Questions