这里演示如何在MVC WEB应用程序如何上传图片到数据库以及如何在WEB页面上显示图片。数据库表对应整个Model类,不单图片数据一个字段,我们从数据表的定义开始:

CREATE TABLE [dbo].[Products] (
[ProductID] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NOT NULL,
[Description] NVARCHAR (MAX) NOT NULL,
[Price] DECIMAL (18, 2) NOT NULL,
[Category] NVARCHAR (MAX) NOT NULL,
[ImageData] VARBINARY (MAX) NULL,
[ImageMimeType] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Products] PRIMARY KEY CLUSTERED ([ProductID] ASC)
);

保存图片的字段为ImageData,类型VARBINARY,字段ImageMimeType保存图片的类型。我们使用Entity framework处理c#对象到数据库的操作,我们不需要编写代码通过SQL代码操作数据库,Entity framework负责数据库的操作。Entity framework支持Model first和Code-first两种方式,Code-first先编写c# model类,然后绑定到数据库,相关的内容可以参见http://msdn.microsoft.com/en-us/data/jj200620

从Model类开始:

public class Product {

        [HiddenInput(DisplayValue = false)]
public int ProductID { get; set; } [Required(ErrorMessage = "Please enter a product name")]
public string Name { get; set; } [DataType(DataType.MultilineText)]
[Required(ErrorMessage = "Please enter a description")]
public string Description { get; set; } [Required]
[Range(0.01, double.MaxValue, ErrorMessage = "Please enter a positive price")]
public decimal Price { get; set; } [Required(ErrorMessage = "Please specify a category")]
public string Category { get; set; } public byte[] ImageData { get; set; } [HiddenInput(DisplayValue = false)]
public string ImageMimeType { get; set; }
}

Entity framework可以在VS中使用nuget package manager安装,安装完entity framework我们创建Entity framework的会话类将Model和数据库联系起来:

using System.Data.Entity;

namespace SportsStore.Domain.Concrete {

    public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
}

我们还需要告诉Entity framework使用哪个数据库,在web.config添加相应的连接字符串:

...
<connectionStrings>
<add name="EFDbContext" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=SportsStore;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
...

接下来创建一个使用EFDbContext操作Model的辅助类:

public interface IProductRepository {

        IQueryable<Product> Products { get; }

        void SaveProduct(Product product);

        Product DeleteProduct(int productID);
} public class EFProductRepository : IProductRepository
{
private EFDbContext context = new EFDbContext(); public IQueryable<Product> Products
{
get { return context.Products; }
} public void SaveProduct(Product product)
{ if (product.ProductID == )
{
context.Products.Add(product);
}
else
{
Product dbEntry = context.Products.Find(product.ProductID);
if (dbEntry != null)
{
dbEntry.Name = product.Name;
dbEntry.Description = product.Description;
dbEntry.Price = product.Price;
dbEntry.Category = product.Category;
dbEntry.ImageData = product.ImageData;
dbEntry.ImageMimeType = product.ImageMimeType;
}
}
context.SaveChanges();
} public Product DeleteProduct(int productID)
{
Product dbEntry = context.Products.Find(productID);
if (dbEntry != null)
{
context.Products.Remove(dbEntry);
context.SaveChanges();
}
return dbEntry;
}
}

定义IProductRepository接口是方便后续使用Dependency injection从接口获取实现类EFProductRepository的实例,这里就不列出具体如何实现。EFProductRepository使用EFDbContext完成添加、保存对象到数据库以及从数据库删除对象。完成数据模型的操作,下面定义控制器的方法:

    public class AdminController : Controller {
private IProductRepository repository; public AdminController(IProductRepository repo) {
repository = repo;
} public ViewResult Index() {
return View(repository.Products);
} public ViewResult Edit(int productId) {
Product product = repository.Products
.FirstOrDefault(p => p.ProductID == productId);
return View(product);
} [HttpPost]
public ActionResult Edit(Product product, HttpPostedFileBase image) {
if (ModelState.IsValid) {
if (image != null) {
product.ImageMimeType = image.ContentType;
product.ImageData = new byte[image.ContentLength];
image.InputStream.Read(product.ImageData, , image.ContentLength);
}
repository.SaveProduct(product);
TempData["message"] = string.Format("{0} has been saved", product.Name);
return RedirectToAction("Index");
} else {
// there is something wrong with the data values
return View(product);
}
} public ViewResult Create() {
return View("Edit", new Product());
} [HttpPost]
public ActionResult Delete(int productId) {
Product deletedProduct = repository.DeleteProduct(productId);
if (deletedProduct != null) {
TempData["message"] = string.Format("{0} was deleted",
deletedProduct.Name);
}
return RedirectToAction("Index");
}
}

这里两个Edit ation,第一个显示编辑上传页面,带HttpPost特性的用于处理编辑页面提交回传,提交的image数据为HttpPostedFileBase类型,我们从中取出图像文件的数据保存到Model类的ImageData属性,ContentType则记录到ImageMimeType属性。对应的Edit视图:

@model SportsStore.Domain.Entities.Product

@{
ViewBag.Title = "Admin: Edit " + @Model.Name;
Layout = "~/Views/Shared/_AdminLayout.cshtml";
} <h1>Edit @Model.Name</h1> @using (Html.BeginForm("Edit", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" })) { @Html.EditorForModel() <div class="editor-label">Image</div>
<div class="editor-field">
@if (Model.ImageData == null) {
@:None
} else {
<img width="150" height="150" src="@Url.Action("GetImage", "Product", new { Model.ProductID })" />
}
<div>Upload new image: <input type="file" name="Image" /></div>
</div> <input type="submit" value="Save" />
@Html.ActionLink("Cancel and return to List", "Index")
}

这里指定表单的enctype=multipart/form-data,缺少这个属性表单提交的数据中会只有图片文件的名称而不包含图片文件的数据。图片显示img单元的src指向一个从product的action生成的网址,我们还需要实现这个方法:

...
public FileContentResult GetImage(int productId) {
  Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId);
  if (prod != null) {
    return File(prod.ImageData, prod.ImageMimeType);
  } else {
    return null;
  }
}
...

这里从图片文件数据和mime类型返回一个FileContentResult。

这就是实现上传图片到数据库的完整过程,实际的应用中我们还需要限制文件大小,通过文件后缀名或者ContentType检查是否是有效的图片文件。

以上内容摘自《Apress Pro ASP.NET MVC 4》第四版,详见原版 http://www.apress.com/9781430242369

ASP.NET MVC 4 - 上传图片到数据库的更多相关文章

  1. 【第一篇】ASP.NET MVC快速入门之数据库操作(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  2. [ASP.NET MVC2 系列] ASP.Net MVC教程之《在15分钟内用ASP.Net MVC创建一个电影数据库应用程序》

    [ASP.NET MVC2 系列]      [ASP.NET MVC2 系列] ASP.Net MVC教程之<在15分钟内用ASP.Net MVC创建一个电影数据库应用程序>       ...

  3. ASP.NET MVC+Entity Framework 访问数据库

    Entity Framework 4.1支持代码优先(code first)编程模式:即可以先创建模型类,然后通过配置在EF4.1下动态生成数据库. 下面演示两种情形: 1.代码优先模式下,asp.n ...

  4. ASP.NET MVC导入excel到数据库

    MVC导入excel和webform其实没多大区别,以下为代码: 视图StationImport.cshtml的代码: @{ ViewBag.Title = "StationImport&q ...

  5. 24、ASP.NET MVC入门到精通——数据库仓储

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 业务层调用数据层对象,我不想每次都new一个数据层对象,而是在数据层创建一个仓储,统一管理所有的对象调用. 1.在IDAL项目中,新建IDB ...

  6. ASP.NET MVC入门到精通——数据库仓储

    业务层调用数据层对象,我不想每次都new一个数据层对象,而是在数据层创建一个仓储,统一管理所有的对象调用. 1.在IDAL项目中,新建IDBSession.tt模板   Ctrl+S后自动生成IDBS ...

  7. ASP.net mvc Code First 更新数据库

    code first 数据库迁移步骤如下: 第一步:Add-Migration DataBase_Init 1. Install-Package EntityFramework.zh-Hans –Ve ...

  8. ASP.NET MVC 4 如何避免数据库被自动创建或自动迁移

    保哥说要想避免数据库被自动创建或自动迁移,可以在Global.asax文件里的Application_Start方法中加入: System.Data.Entity.Database.SetInitia ...

  9. Asp.net mvc+EF+Sql Server2008数据库缓存依赖

    1.开启数据库缓存依赖功能(开启对数据库中表Article和ArticleType的缓存) (注:)如果要配置SqlCacheDependency,则需要以命令行的方式执行. aspnet_regsq ...

随机推荐

  1. Codeforces Round #406 (Div. 1) B. Legacy 线段树建图跑最短路

    B. Legacy 题目连接: http://codeforces.com/contest/786/problem/B Description Rick and his co-workers have ...

  2. ftp命令详解补充

     下面我来详细地介绍一个登陆FTP的命令和步骤吧: FTP命令是Internet用户使用最频繁的命令之一,不论是在DOS还是UNIX操作系统下使用FTP,都会遇到大量的FTP内部命令.熟悉并灵活应用F ...

  3. 第一章 flex单词计数程序

    学习Flex&Bison目标, 读懂SQLite中SQL解析部分代码 Flex&Bison简介Flex做词法分析Bison做语法分析 第一个Flex程序, wc.fl, 单词计数程序 ...

  4. CentOS 7卸载Docker

    1.先查询所有安装的包 yum list installed | grep docker*或者rpm -qa docker* 2.删除查询出来的包 # 一般情况会有一个 yum remove -y d ...

  5. Redis在SSM项目中的简单使用

    一.基于SSM的Redis环境配置 前提是你的开发电脑安装和配置好了redis,如果没安装请看Window配置Redis环境和简单使用 1.1.pom文件中引入redis客户端jar包(pom.xml ...

  6. 添加script标签、添加事件

    添加script标签 var _hmt = _hmt || [];    (function () {        var hm = document.createElement("scr ...

  7. windows多线程同步--事件

    推荐参考博客:秒杀多线程第六篇 经典线程同步 事件Event   事件是内核对象,多用于线程间通信,可以跨进程同步 事件主要用到三个函数:CreateEvent,OpenEvent,SetEvent, ...

  8. 【Zookeeper】源码分析之服务器(二)之ZooKeeperServer

    一.前言 前面阐述了服务器的总体框架,下面来分析服务器的所有父类ZooKeeperServer. 二.ZooKeeperServer源码分析 2.1 类的继承关系 public class ZooKe ...

  9. sql中索引不会被用到的几种情况

    1.查询谓词没有使用索引的主要边界,换句话说就是select *,可能会导致不走索引. 比如,你查询的是SELECT * FROM T WHERE Y=XXX;假如你的T表上有一个包含Y值的组合索引, ...

  10. Photodesk for Mac(Instagram 桌面客户端)破解版安装

    1.软件简介    PhotoDesk - for Instagram 是 macOS 系统上一款 Instagram 客户端,可以让大家在 Mac 上观看朋友的新照片.或是最近热门的作品,也可以 f ...