这里演示如何在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. POST数据中有特殊符号导致数据丢失的解决方法

    使用Ajax传送数据时,当数据中存在加号(+).连接符(&)或者百分号(%)时,服务器端接收数据时会丢失数据.分析Ajax传送数据的格式与Javascript的语法: 1. "+&q ...

  2. 转载:Gitlab备份和恢复操作记录

    转载:Gitlab备份和恢复操作记录 包含了备份和数据恢复的操作记录,实验可行 前面已经介绍了Gitlab环境部署记录,这里简单说下Gitlab的备份和恢复操作记录: 1)Gitlab的备份目录路径设 ...

  3. Java中的ReentrantLock和synchronized两种锁定

    原文:http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html 多线程和并发性并不是什么新内容,但是 Java 语言设计中的创新之 ...

  4. nohup和disown

    Many system administrators make a practice of using GNU Screen or tmux to manage jobs running in the ...

  5. caffe.pb.h丢失问题解决方法

    https://blog.csdn.net/ThomasCai001/article/details/53940430 错误提示   fatal error: caffe/proto/caffe.pb ...

  6. android-activity生命周期方法

    整个Activity生命周期中的所有方法,我们可以根据程序的需要来覆盖相应的方法: public class Activity extends ApplicationContext { //创建的时候 ...

  7. linux远程开启不挂起的服务

    解决Linux关闭终端(关闭SSH等)后运行的程序自动停止 λ nohup --help Usage: nohup COMMAND [ARG]... or: nohup OPTION Run COMM ...

  8. vue中使用some删除list中的数据

    在vue中可以使用some方法查找需要删除的所以 this.list.some((item, i) => { if (item.id == id) { this.list.splice(i, 1 ...

  9. java 获取系统当前时间并格式化

      java 获取系统当前时间并格式化 CreateTime--2018年5月9日11:41:00 Author:Marydon 实现方式有三种 updateTime--2018年7月23日09点32 ...

  10. mysql数据库自增id重新从1排序的两种方法

    mysql默认自增ID是从1开始了,但当我们如果有插入表或使用delete删除id之后ID就会不会从1开始了哦.   使用mysql时,通常表中会有一个自增的id字段,但当我们想将表中的数据清空重新添 ...