0

I'm trying to save data after i edited back to database. The problem is with the file upload. I have to upload new image everytime i want to save edited data otherwise the controller would think that my img property is null. So i rewrite my edit action to like this, hoping it'd use my uploaded image

[HttpPost]
        [ValidateAntiForgeryToken]
        [ValidateInput(false)]
        public ActionResult Edit([Bind(Include = "id,name,info,whatThisTeach,whatToKnow")] Major major, HttpPostedFileBase img)
        {

            if (ModelState.IsValid)
            {
                if(img != null)
                {
                    major.img = new byte[img.ContentLength];
                    img.InputStream.Read(major.img, 0, img.ContentLength);
                }
                else
                {
                    var m = db.Majors.Find(major.id);
                    major.img = m.img;              
                }
                db.Entry(major).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View("Details", major);
        }

But when i try to edit data without uploading new image, it gave me this error:

System.InvalidOperationException HResult=0x80131509
Message=Attaching an entity of type 'MUC.Models.Major' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate. Source=EntityFramework StackTrace:
at System.Data.Entity.Core.Objects.ObjectContext.VerifyRootForAdd(Boolean doAttach, String entitySetName, IEntityWrapper wrappedEntity, EntityEntry existingEntry, EntitySet& entitySet, Boolean& isNoOperation) at System.Data.Entity.Core.Objects.ObjectContext.AttachTo(String entitySetName, Object entity) at System.Data.Entity.Internal.Linq.InternalSet1.<>c__DisplayClassa.<Attach>b__9() at System.Data.Entity.Internal.Linq.InternalSet1.ActOnSet(Action action, EntityState newState, Object entity, String methodName) at System.Data.Entity.Internal.Linq.InternalSet1.Attach(Object entity)
at System.Data.Entity.Internal.InternalEntityEntry.set_State(EntityState value) at System.Data.Entity.Infrastructure.DbEntityEntry
1.set_State(EntityState value) at MUC.Controllers.MajorsController.Edit(Major major, HttpPostedFileBase img) in C:\Users\miike\Desktop\MUC\MUC\Controllers\MajorsController.cs:line 101 at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) at System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase1.End() at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.b__3d() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.b__3f()

and here's my Edit view:

@model MUC.Models.Major

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Edit</title>
</head>
<body>
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/jquery.validate.min.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
    <script src="~/Scripts/ckeditor/ckeditor.js"></script>


    @using (Html.BeginForm("Edit", "Majors", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        @Html.AntiForgeryToken()

        <div class="form-horizontal">
            <h4>Major</h4>
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-group">
                @Html.LabelFor(model => model.img, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @if (Model.img != null)
                    {
                        var base64 = Convert.ToBase64String(Model.img);
                        var imgsrc = string.Format("data:image/jpg;base64,{0}", base64);
                        <img src="@imgsrc" /><br/>
                        <input type="file" id="img" name="img"/>
                    }
                    else
                    {
                        <input type="file" id="img" name="img"/>
                    }

                    @Html.ValidationMessageFor(model => model.img, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.name, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.name, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.name, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.info, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.info, new { htmlAttributes = new { @id = "info", @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.info, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.whatThisTeach, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.TextAreaFor(model => model.whatThisTeach, new { htmlAttributes = new { @class = "form-control", @id = "whatThisTeach" } })
                    <script type="text/javascript">CKEDITOR.replace('whatThisTeach');</script>
                    @Html.ValidationMessageFor(model => model.whatThisTeach, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.whatToKnow, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.TextAreaFor(model => model.whatToKnow, new { htmlAttributes = new { @class = "form-control", @id = "whatToKnow" } })
                    <script type="text/javascript">CKEDITOR.replace('whatToKnow');</script>
                    @Html.ValidationMessageFor(model => model.whatToKnow, "", new { @class = "text-danger" })
                </div>
            </div>

            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Save" class="btn btn-default" />
                </div>
            </div>
        </div>
    }

    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
</body>
</html>
m5kev4n
  • 541
  • 1
  • 8
  • 20
  • You taking the wrong approach. You are editing data so ALWAYS use a view model, and in the POST method you get you data model from the data base and update its properties from the view model - [What is ViewModel in MVC?](https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  May 06 '18 at 08:22
  • @StephenMuecke Im not quite sure i understand what u meant. But to take my approach. Isnt there anyway that we could maybe just set an instance for the image field when no image is uploaded. – m5kev4n May 06 '18 at 08:37
  • Did you read the link (and it makes not difference if there is another approach - the correct approach is to use view model) –  May 06 '18 at 08:38

1 Answers1

0

your code has a problem because img is null and you pass it again => major.img = m.img;