这里演示如何在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. windows 下重置 mysql 的 root 密码

    今天发现 WordPress 连接不上数据库,登录 window server 服务器查看,所有服务均运行正常. 使用 root 账号登录 mysql 数据库,结果提示密码不匹配.我突然意识到,服务器 ...

  2. boost 1.67编译VS2017版本

    最近想系统学习并使用一下boost的asio异步网络库,所以需要编译boost库使用,下面简单介绍如何编译. 编译环境 boost1.67版本,windows 10,VS2017 下载boost 建议 ...

  3. 树莓派.Qt.Creator安装方法

    树莓派硬件: Raspberry Pi 3 B 树莓派系统: Linux version 4.9.59-v7+ (32位) Qt版本(x86版本--32位): 安装过程 可以查看软件仓库支持的版本: ...

  4. firedac数据集数据序列为JSON

    firedac数据集数据序列为JSON FIREDAC数据库引擎充分地考虑了跨平台和跨语言的支持. 因此,FIREDAC数据集可以序列为BIN\XML\JSON,三种格式. firedac数据集数据序 ...

  5. ZegGraph属性含义

    一.主要内容概念 属性名称 属性值.作用 MasterPane 一个类对象管理多个GraphPane来源于PaneBase.使用MasterPane类都是可选的,GraphPane类可以直接用于一个单 ...

  6. OKHttpUtil工具类

    导入jar包下载链接 http://square.github.io/okhttp/ package com.common.util; import java.io.IOException; impo ...

  7. 9.5 dubbo事件通知机制

    dubbo事件通知机制:http://dubbo.io/books/dubbo-user-book/demos/events-notify.html 一.使用方式 两个服务: DemoService: ...

  8. Unity Alpha融合参数(便查)

    Alpha Blending,中文译作Alpha混合 Blending就是控制透明的.处于光栅化的最后阶段. 这里例如我们给一个模型贴一个材质,那么在某个点计算出来颜色值称为源,而该点之前累积的颜色值 ...

  9. angularjs 动态表单, 原生事件中调用angular方法

    1. 原生事件中调用angular方法, 比如 input的onChange事件想调用angular里面定义的方法 - onChange="angular.element(this).sco ...

  10. 使用go语言操作db2

    操作系统 : CentOS7.3.1611_x64 go语言版本:1.8.3 linux/amd64 db2版本: db2_v101_linuxx64_expc 问题描述 怎么使用go语言在CentO ...