这里演示如何在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. AngularJS中写一个包裹HTML元素的directive

    有这样的一个场景,这里有一个表单: <form role="form">    ...</form> 我们希望在form的外层动态包裹上一层. 有可能是这样 ...

  2. Tomcat热部署SpringMVC项目出错

    一.问题 项目照常跑,没有什么大的影响,但是在控制台却出现了错误,具体信息如下图所示 二.解决方法 原因分析:很多人已经说的很明白了,这大概是因为项目文件很多,在tomcat重启的时候,之前的tomc ...

  3. Web 前端面试题整理(不定时更新)

    重要知识需要系统学习.透彻学习,形成自己的知识链.万不可投机取巧,临时抱佛脚只求面试侥幸混过关是错误的! 面试有几点需注意: 面试题目: 根据你的等级和职位的变化,入门级到专家级,广度和深度都会有所增 ...

  4. JNI学习小结

    Java中类型与C/C++中对应关系   Java中的类的对应   Sign签名, 用来识别对应各个方法. JDK下的javap.exe能输出签名.用法javap -s -p 完整类名     下面是 ...

  5. Duplicate复制数据库并创建物理StandBy(spfile版本)

    过程和Duplicate复制数据库并创建物理StandBy类似,只是不需要重启数据库. 目的:创建standby,不重启源数据库 1设定环境如下: Primary数据库 IP 172.17.22.16 ...

  6. ASP.NET MVC 一款可预览、裁剪头像上传组件

    今天介绍一款Web上常用的头像上传组件,常用于头像上传时对用户上传的图片进行裁剪并实时预览,最终效果如下: 源代码结构: Github地址: https://github.com/FrankFan/A ...

  7. Emacs 设置C++代码风格

    ;; C++代码风格设置 (defconst cobbcpp '("linux" ; this is inheritance from the linux style (c-bas ...

  8. TLS/HTTPS 证书生成与验证

    最近在研究基于ssl的传输加密,涉及到了key和证书相关的话题,走了不少弯路,现在总结一下做个备忘 科普:TLS.SSL.HTTPS以及证书 不少人可能听过其中的超过3个名词,但它们究竟有什么关联呢? ...

  9. [Aaronyang] 写给自己的WPF4.5 笔记7[三巴掌-ItemsControl数据绑定详解与binding二次处理 3/3]

    我要做回自己--Aaronyang的博客(www.ayjs.net) 博客摘要: 全方位的讲解了转换器的使用,单值,多值转换器,条件转换器,StringFormat等方式 详细的实践地讲解了Items ...

  10. Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果

    大家好!过完年回来到现在差不多一个月没写文章了,一是觉得不知道写哪些方面的文章,没有好的题材来写,二是因为自己的一些私事给耽误了,所以过完年的第一篇文章到现在才发表出来,2014年我还是会继续在CSD ...