Reputation: 900
I use Entity Framework in asp.net MVC 5 (vb.net) to store some data including an image (png). The images can be saved to the database as Byte(), but as soon I edit any existing entity without uploading a new image, the stored image is deleted. So I tried this and wrote following code in the edit controller:
If ModelState.IsValid Then
If Request.Files("Image").ContentLength <> 0 Then
dbModel.Image = dbModel.ImageToByte(Request.Files("Image")) 'Function to create Byte() --> this works
Else
dbModel.Image = db.Content.Find(dbModel.ID).Image 'This line is responsible for the exception
End If
db.Entry(dbModel).State = EntityState.Modified 'Here the exception occours!
db.SaveChanges()
Return RedirectToAction("Index")
End If
In the line, where the EntityState is set to Modified, an exception occured:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: Attaching an entity of type 'myDatabase.dbModel' 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.
I guess, that the line where the existing image is loaded from the database is responsible for the exception, but I really don't know what to do.
Upvotes: 0
Views: 735
Reputation: 900
Finally I ended up with this solution.
Function Edit(<Bind(Include:="ImageFile,Image")> ByVal Model As dbModel, ByVal ImageFile As HTTPPostedFileBase) As ActionResult
If ModelState.IsValid Then
Dim Current As dbModel = db.Content.Find(Model.ID) 'Get the original entry.
If Not ImagFile is Nothing Then
Model.Image = Model.ImageToByte(ImageFile) 'Function to create Byte()
Else
Model.Image = db.Content.Find(Model.ID).Image
End If
'db.Entry(dbModel).State = EntityState.Modified 'Here the exception occoured before.
db.Entry(Current).CurrentValues.SetValues(Model) 'This line is new and solved the problem!
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(Model)
End Function
For the sake of completeness, here's the code to convert HTTPPostedFileBase to Byte():
Public Function ImageToByte(ByVal Img As HttpPostedFileBase) As Byte()
Dim Image As New MemoryStream
Img.InputStream.CopyTo(Image)
Return Image.ToArray()
End Function
Upvotes: 0
Reputation: 239300
Use view models. The problem you're having is occurring because the Image
field is posted back as null, since no new image was set, so when you update the entity, it sets Image
to that null value. In effect, by not posted a value of Image
, you are literally telling Entity Framework that you want to null this value out.
By using a view model, you can only deal with the fields you need to in your view, and then map the posted values back onto your entity. That means properties like Image
would still have their value as retrieved from the database. For example:
public class FooViewModel
{
// other properties here
public HttpPostedFileBase Image { get; set; }
}
Then in your action:
public ActionResult Edit(int id, FooViewModel model)
{
var foo = db.Foos.Find(id);
if (foo == null)
{
return new HttpNotFoundResult();
}
// Map properties over
// foo.Bar = model.Bar;
if (model.Image != null && model.Image.ContentLength > 0)
{
foo.Image = foo.ImageToByte(model.Image);
}
...
}
Upvotes: 1