سؤال

I have a small demo application to work around Binary data stored in the database. See below for related code:

Entity Class:

    [HiddenInput(DisplayValue = false)]
    public int Id { get; set; }

    [Display(Name = "Full Name:")]
    public string Name { get; set; } 

    [DataType(DataType.Upload)]
    [Display(Name = "Photo:")]
    public byte[] ImageData { get; set; }

    [HiddenInput(DisplayValue = false)]
    public string ImageMimeType { get; set; }

Edit Action:

   [HttpGet]
   public ActionResult Edit(int id)
    {
         var mensPlayer = _dataSource.MensPlayers.FirstOrDefault(p => p.Id == id);

        return View(mensPlayer);
    }

    [HttpPost]
    public ActionResult Edit(MensPlayer mensPlayer, HttpPostedFileBase image)
    {
        if (ModelState.IsValid)
        {
           //Added line below
            _dataSource.ImageTemp(mensPlayerInDb, mensPlayer);
            if (image != null)
            {
                mensPlayer.ImageMimeType = image.ContentType;
                mensPlayer.ImageData = new byte[image.ContentLength];
                image.InputStream.Read(mensPlayer.ImageData, 0, image.ContentLength);
            }
              //Added line below
             mensPlayer.ImageData = mensPlayerInDb.ImageData;

            //Save Player
            _dataSource.Update(mensPlayer);
           _dataSource.Save();
          TempData["message"] = string.Format("{0} has been saved", mensPlayer.Name);
            return RedirectToAction("Detail", "MensPlayer", new {id = mensPlayer.Id});
        }
        return View(mensPlayer);
    }

GetImage Method:

public FileContentResult GetImage(int id)
    {
        var image = _dataSource.MensPlayers.FirstOrDefault(p => p.Id == id);
        if (image != null)
        {
            return File(image.ImageData, image.ImageMimeType);
        }
        return null;
    }

Display Image:

@if (Model.ImageData != null) {
    <div >
         <img width="300" height="400" src="@Url.Action("GetImage", "MensPlayer",
                                        new { Model.Id })" alt="Player Image"/>
     </div>
 }

DataSource class

public interface IDataSource
{
    IQueryable<MensTeam> MensTeams { get; }
    IQueryable<MensPlayer> MensPlayers { get; }
    IQueryable<MensHome> MensHomes { get; }
    void Save();
    void Update(MensPlayer mensPlayer);
    void Delete();
    void ImageTemp(MensPlayer mensPlayerInDb, MensPlayer mensPlayer);//I added this
}

In Db class

void IDataSource.Save()
    {
        SaveChanges();
    }

    void IDataSource.Update(MensPlayer mensPlayer)
    {
        Entry(mensPlayer).State = EntityState.Modified;
    }
     //Added code below
    void IDataSource.ImageTemp(MensPlayer mensPlayerInDb, MensPlayer mensPlayer)
    {
        Entry(mensPlayerInDb).CurrentValues.SetValues(mensPlayer);
    }

My problem is, every time i try to edit a player, every data is nicely retrieved from the database but when i hit save after editing, the ImageData is lost, more like replacing the original data with null value. It's like, the application expects me to re-upload the image at every edit i attempt.

What can i do to clean this up?

هل كانت مفيدة؟

المحلول

Well, if image is null then in your entity mensPlayer.ImageData is null. Later when you call _dataSource.Update(mensPlayer) you set the state of the entity to Modified (at least I guess that Update just sets the state to Modified), so you are telling EF that your have modified the image too (namely set it to null) and EF will save that change.

In order to solve the problem you can either load the entity including the image from the database first...

var mensPlayerInDb = context.MensPlayers.Find(mensPlayer.Id);
mensPlayer.ImageData = mensPlayerInDb.ImageData; // save the ImageData
// copy changed values to loaded entity and save it, ImageData is unchanged
context.Entry(mensPlayerInDb).CurrentValues.SetValues(mensPlayer);
context.SaveChanges();

...or you can try:

context.Entry(mensPlayer).State = EntityState.Modified;
context.Entry(mensPlayer).Property(m => m.ImageData).IsModified = false;

The latter approach didn't work with EF < 5.0 (because it was forbidden to set the Modified state of a property to false once the entity was marked as Modified) but it should work with EF 5.

You need to integrate one of the solutions into your _dataSource service class, possibly by introducing new methods because it won't work with your general Update method.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top