首先,我个人不提倡把图片存在数据库中,尤其是在web站点项目里,因为文件系统的访问更加直接,并且可以得到许多优化,而数据库除了安全性好(适合保存一些保密的图片),其他都没文件系统方便。

如果一定要在SQL Server中存取图片,请看这个例子。

首先,图片的存储实际上是字节流的形式,SQL Server给我们提供了image类型,可以用来保存图片,所以建立的表结构如下,Pic是image类型的字段:

CREATE TABLE [dbo].[ImgTest]
(
    [Id]   [uniqueidentifier] NOT NULL,
    [Pic]  [image] NOT NULL,
    CONSTRAINT [PK_ImgTest] PRIMARY KEY CLUSTERED([Id] ASC)WITH (
        PAD_INDEX = OFF,
        STATISTICS_NORECOMPUTE = OFF,
        IGNORE_DUP_KEY = OFF,
        ALLOW_ROW_LOCKS = ON,
        ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

接下来,用Entity Framework对这张表做一下ORM(不是本文讲解范围,具体过程省略)。最终,ImgTest表对应的实体类如下:

namespace EFImgTest.Models
{
    using System;
    using System.Collections.Generic;

    public partial class ImgTest
    {
        public System.Guid Id { get; set; }
        public byte[] Pic { get; set; }
    }
}

我们发现,Pic字段已经被映射成了byte[]数组。所以我们不管是读取还是存储,都需要面对byte[]到图片的转换问题。

一、将图片上传到数据库

第一步是做图片上传,在MVC3中做文件上传要注意指定Form的enctype为multipart/form-data,这样才能在controller中取到图片或其他文件。请看视图文件的代码:

@using (Html.BeginForm("Create", "ImgTest", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>ImgTest</legend>
        <input type="file" name="imgFile" id="imgFile" />
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

在BeginForm方法的重载中,可以指定enctype = "multipart/form-data"。不过这个重载要求我们同时显式指定Controller和Action的名字。

而在Controller中,我们需要多加一个参数“HttpPostedFileBase imgFile”,用来接收用户上传的图片。然后使用HttpPostedFile.InputStream.Read方法,将图片的数据撸到一个二进制流中。这样就可以给ImgTest实体的Pic属性赋值了。

Controller的代码如下:

[HttpPost]
public ActionResult Create(ImgTest imgtest, HttpPostedFileBase imgFile)
{
    if (ModelState.IsValid)
    {
        if (imgFile.ContentLength > 0)
        {
            var imgByte = new byte[imgFile.ContentLength];
            imgFile.InputStream.Read(imgByte, 0, imgFile.ContentLength);
            imgtest.Id = Guid.NewGuid();
            imgtest.Pic = imgByte;
            db.ImgTest.Add(imgtest);
            db.SaveChanges();
        }
        return RedirectToAction("Index"); 
    }
    return View(imgtest);
}

上传完毕之后,数据库里插入的记录如下:

这里插句题外话,如果要手动使用SQL语句插入图片,可以这样做:

INSERT INTO ImgTest
  (
    Id,
    Pic
  )
SELECT NEWID(),
       BulkColumn
FROM   OPENROWSET(BULK 'D:\Edi\tempfolder\Capture.PNG', SINGLE_BLOB) AS Pic

二、从byte[]读取图片

读取图片时,Razor引擎没有提供方法直接读取Model中的byte[]类型属性作为图片输出,所以我们要自己写个Action,将byte[]转换为图片类型的FileContentResult返回出去:

public ActionResult GetImage(Guid id)
{
    var imgByte = db.ImgTest.Find(id).Pic;
    return new FileContentResult(imgByte, "image/jpeg");
}

视图中的调用方法:

<img data-original="@Url.Content("~/ImgTest/GetImage/" + item.Id)" />

效果如下: