1

I want to capture picture from canvas, make it base64 and save it into db. Is it possible to save base64 directly to table? This is where I came already:

VIEW:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image0");
ctx.drawImage(img, 0, 0);
//drawing image into myCanvas

var imag = canvas.toDataURL("image/png");
//making base64 from that image

document.getElementById('imag').value = imag;
//passing base64 to @Html.TextAreaFor(model => model.IMG, new {id = "imag"}) prior to submitting

MODEL:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;

namespace myApp.Models
{ 
public class MYCLASS
    {
     public int ...
     public string ...
     public string IMG { get; set; }
    }
}

CONTROLLER:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult myImageToDB(MYCLASS myclass)
{

   if (ModelState.IsValid)
   {
      db.MYCLASSs.Add(myclass);
      db.SaveChanges();
      //here it fails on db.SaveChanges()
      return RedirectToAction("Detail", "M35");
   }
   return View(myclass);
}

When submitted I got only this answer from MS VS:

System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities.

The problem occured when I have added

public string IMG { get; set; }

into the model. And when I now disable

document.getElementById('imag').value = imag;

everything works just fine.

thx

nevo
  • 47
  • 2
  • 7
  • What does the model on the server look like? It appears you have specified validation rules. – Andy T Nov 22 '13 at 15:28
  • Your error is a EF error, please provide more details – radu florescu Nov 22 '13 at 15:28
  • I have added some extra details. Pls let me know if something more is needed. thx – nevo Nov 22 '13 at 15:53
  • please look at this question to find out what your validation errors actually are - http://stackoverflow.com/questions/5400530/validation-failed-for-one-or-more-entities-while-saving-changes-to-sql-server-da – Tommy Nov 22 '13 at 16:36
  • Floradu88, Tommy, so you would say that there is no problem with the code itself but with the EF? Tommy, I will need 'translator' for the link you posted, didn't yet get it from the answers there :) – nevo Nov 22 '13 at 17:24
  • Tommy, in my opinion the validation error is cased by the base64 data I am trying to save to db via `public string IMG {get;set;}`. Wen the base64 data are not passed to IMG then everything works just fine. Is the 'string' not capable of storing base64 data? – nevo Nov 25 '13 at 06:34
  • @Tommy, one good sleep and I already got that. I received this after implementing it into my app: _Property: IMG Error: The field IMG must be a string or array type with a maximum length of '4000'._ – nevo Nov 25 '13 at 12:13
  • @nevo - Sorry I am just seeing your messages. What the error is telling you is that your database field is set to have a max length of 4000 chars. Are you using code first or database first in your EF implementation? – Tommy Nov 25 '13 at 15:19

2 Answers2

1

Based on your error message, the error is occuring because your model doesn't fit the database rules. For instance, you are sending a null to a non-nullable value or you are trying to put too much information in a column (255 bytes in a 128 byte column). Use the information located in this link to help you discover exactly what property of the entity is failing - Validation failed for one or more entities while saving changes to SQL Server Database using Entity Framework

Now that you have done that, I see that your actual entity error is

IMG Error: The field IMG must be a string or array type with a maximum length of '4000'.

varchar(n|MAX) has a limit of 4000 IF you specify an integer when you declare it (varchar(4000)). However, using varchar(MAX) gives you 2GB of storage in that one field per record. With that, we need to look to see if you are using code first or database first in your EF implementation. If you are using code first, annotate your column with varchar(MAX) like seen below.

[Column(TypeName = "varchar(MAX)")]
public string Img {get;set;}

If you are using database first, then go to your database (Sql Management Studio), right click the table and choose design. Update the image field to varchar(MAX) as the type and save. In order to update EF, open your EF designer, delete the existing Images table, then right click the surface and choose Update model from Database and follow the steps to re-add your table.

EDIT

Based on the OP's response, we should cover how to make a large varchar column in SQL CE as well. For doing code first against SQL CE, use the following code snippet:

[Column(TypeName = "ntext")]
[MaxLength] 
public string Img {get;set;}
Community
  • 1
  • 1
Tommy
  • 39,592
  • 10
  • 90
  • 121
  • thanks for your detailed answers. That was it. For my app development I use SQL CE (didn't stated it in my Q) so in the end I found out it is _ntext_ for SQL CE (_varchar(MAX)_ then for SQL Server). But works just fine and I have base64 data already stored in my db column :) Final code snippet for SQL CE _[Column(TypeName = "ntext")] public string Img {get;set;}_ – nevo Nov 26 '13 at 06:23
  • @nevo - awesome, I updated my answer to cover SQL CE as well! – Tommy Nov 26 '13 at 15:03
  • bad news. I, unfortunately, did somehow cripple (shorten) the base64 string before saving it. That's why I was able to save it to _"ntext" string_ as I mentioned above. After I corrected the mistake I again receive the _The field IMG must be a string or array type with a maximum length of '4000'_ error no matter the Img string is ntext. I am afraid that SQL CE will not 'eat' that long string like base64. Or there is some other problem (needs to be decoded/encoded??) ... – nevo Nov 27 '13 at 15:16
  • Can you use the Image type column? http://msdn.microsoft.com/en-us/library/ms172424(SQL.110).aspx – Tommy Nov 27 '13 at 15:32
  • @nevo - In addition to the above comment, take a look at this SO question as well - http://stackoverflow.com/questions/15329877/entityframework-5-model-first-and-sqlce-what-type-property-to-store-an-imag – Tommy Nov 27 '13 at 15:39
  • Also Image does not work. It seems I need to do some workaround or what described here [stackoverflow.com/questions/5737733/](http://stackoverflow.com/questions/5737733/error-storing-image-in-sql-ce-4-0-with-asp-net-mvc-3-and-entity-framework-4-1-co) but yet do not understand how... – nevo Nov 27 '13 at 16:50
  • here is described the little thing missing [Saving images and long strings to SQL Server Compact with Entity Framework 4.1 Code First](http://erikej.blogspot.sk/2011/04/saving-images-to-sql-server-compact.html). **[MaxLength]** is doing the job of unlocking the vast spaces for the base64. Like this **[Column(TypeName = "ntext")] [MaxLength] public string Img {get;set;}** Finally I am able to store and again display the image from db. Thanks – nevo Nov 27 '13 at 17:23
  • @nevo - i made the edit you proposed since it was community rejected. Thanks for the info - now we have a complete answer! – Tommy Nov 27 '13 at 18:48
0

Is there a reason you need Base64? It adds overhead to having to encode and decode that out of the database. If you can, it may be better to simply store the image data (un-encoded) as a binary blob in the database. That is, if your images are of a small size.

Microsoft provides a good document (https://research.microsoft.com/pubs/64525/tr-2006-45.pdf) called "To BLOB or not to BLOB" about whether you should store images in a database. The basic rule is if you image is 256KB or less, it is OK to store in DB. If bigger than 1MB, then it is better to store the images on the filesystem and serve them directly from there in your server.

MS SQL Server 2012 can automatically manage filesystem storage of binary data for you with its new FILETABLE feature: http://blogs.msdn.com/b/mvpawardprogram/archive/2012/07/23/sql-server-2012-migrating-blobs-to-filetables.aspx

nemik
  • 658
  • 6
  • 5
  • what if they are larger than 256KB but less than 1MB? :) – Tommy Nov 22 '13 at 16:13
  • the reason I want to store it directly to db is that not all records after they are created will be 'saved' for the later. So if I will have images stored in the filesystem, I then need to delete the db record and also image from filesystem instead of just deleting only the db record. And yes, the pictures will be 256KB or less. – nevo Nov 22 '13 at 16:14
  • nevo, I understand. But if your images are larger than 1MB, your performance may suffer. It's OK, storing in DB is just fine. But for better performance, don't bother with base64, just store as a blob. In SQL Server version prior to 2012, they even offer an "IMAGE" type: http://technet.microsoft.com/en-us/library/ms187993.aspx If you're fortunate enough to use Server 2012, its new FILETABLE can give you the best of both worlds. It manages the data on the filesystem for you! http://blogs.msdn.com/b/mvpawardprogram/archive/2012/07/23/sql-server-2012-migrating-blobs-to-filetables.aspx – nemik Nov 22 '13 at 16:20
  • I would say that I am just curious if this new approach will or will not be easier for programming. Storing images into filesystem I have already tried in my previous app. – nevo Nov 22 '13 at 16:22
  • @nemik, thanks also for your answers. Wish I have bigger reputation so I will mark your tip as useful. I am keeping the filesystem storing as backup. One never knows :) – nevo Nov 26 '13 at 07:36