65.9K
CodeProject 正在变化。 阅读更多。
Home

使用存储过程和C#在SQL Server中存储和检索图像

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (52投票s)

2012年3月28日

GPL3

6分钟阅读

viewsIcon

413221

downloadIcon

16596

一篇关于如何使用存储过程和 C# 从 SQL Server 2008 存储和检索图像的介绍。

引言

首先,我必须告诉您,我不是专家,但我会尽力解释解决方案。在这篇文章中,我将解释如何使用 C# 作为前端编程语言和存储过程作为 SQL Server 后端语言,从 SQL Server 数据库存储和检索图像。撰写关于此主题文章的原因是给初学者一个正确的理解。

必备组件

您需要对存储过程和 C# 语言有基本的了解。

使用的工具

  • SQL Server 2008
  • Visual Studio 2010
  • C# (Windows 窗体应用程序)

准备开发环境

SQL Server 环境

创建表

在此示例中,我将只使用一个名为 ImageData 的表,它只包含两个字段:ImageIDImageData,这些字段的数据类型为 int image。使用下面的 SQL 脚本创建表。

 CREATE TABLE [dbo].[ImageData]
 (
    [ImageID] [int] IDENTITY(1,1) NOT NULL,
    [ImageData] [image] NULL,
 CONSTRAINT [PK_ImageData] PRIMARY KEY CLUSTERED 
 (
    [ImageID] 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]
  
创建存储过程

在此示例中,我将使用四个(4)个存储过程,分别名为 ReadAllImage, ReadAllImageIDs, ReadImage, SaveImage,并使用以下 SQL 脚本创建这些过程。

CREATE proc [dbo].[ReadAllImage] as 
SELECT * FROM ImageData 
GO
CREATE proc [dbo].[ReadAllImageIDs] as 
SELECT ImageID FROM ImageData 
GO
CREATE proc [dbo].[ReadImage] @imgId int as 
SELECT ImageData FROM ImageData 
WHERE ImageID=@imgId 
GO 
CREATE proc [dbo].[SaveImage] @img image as
INSERT INTO ImageData(ImageData)
VALUES (@img)
GO

Visual Studio 环境

 

创建 Windows 窗体

在此示例中,我将只使用一个窗体,并根据下表设置基本属性。

 

控件名称 属性名称 属性值

表单

名称 UsingSPs
  文本 使用 C#.NET 从 SQL Server 存储和检索图像
Button1 名称 btnLoadAndSave
  文本 <<--加载和保存图像-->>
Button2 名称 btnRefresh
  文本 刷新
Button3 名称 btnDisplayImage
  文本 显示图像
ComboBox 名称 cmbImageID
GroupBox 名称 grbPicBox
  文本 图像显示
  Anchor 顶部、底部、左侧、右侧
PictureBox 名称 picImage
  Dock Fill

 

开始编码

现在我们已经具备了开始编码的所有条件,这是我们需要高度关注开发的部分。无论如何,我将尽力解释编码,那么,让我们开始我们的旅程吧。

在此示例中,除了窗体之外,我还会使用一个名为 DBHandler 的类,该类的目的是处理数据库连接详细信息。这是该类的代码。

处理数据库连接字符串

public class DBHandler
{        
  public static string SrvName = @"DBSERVER"; //Your SQL Server Name
  public static string DbName = @"DB";//Your Database Name
  public static string UsrName = "us";//Your SQL Server User Name
  public static string Pasword = "xxxx";//Your SQL Server Password
        
  /// <summary>
  /// Public static method to access connection string throw out the project 
  /// </summary>
  /// <returns>return database connection string</returns>
  public static string GetConnectionString()
  {
     return "Data Source=" + SrvName + "; initial catalog=" + DbName + "; user id=" 
     + UsrName + "; password=" + Pasword + ";";//Build Connection String and Return
  }
}

选择图像并存储到数据库

在开始编码之前,请在代码中添加以下命名空间。

using System.IO;
using System.Data;
using System.Data.SqlClient;

在这里,我将逐步解释 btnLoadAndSave 按钮的单击事件过程。

  1. 创建与数据库的连接。
  2. 创建类型为 OpenFileDialog 的对象 fop
  3. 设置对象 fop 的 InitialDirectory 属性。
  4. 设置对象 fop 的 Filter 属性。(在这里用户只能选择 .jpg 文件)
  5. 向用户显示打开文件对话框,只有当用户选择一个图像时,才会进入 if 块。
  6. 创建一个文件流对象 FS ,并将其与用户选择的文件关联。
  7. 创建一个大小等于用户选择的文件流长度的字节数组。
  8. 将用户选择的文件流读取到字节数组中。
  9. 检查与数据库的连接是否已关闭。
  10. 如果连接已关闭,则仅打开连接。
  11. 通过传递存储过程名称和数据库连接来创建一个 SQL 命令对象 cmd
  12. cmd 对象的 CommandType 属性设置为存储过程类型。
  13. cmd 对象添加参数并为其设置值。
  14. 通过调用对象 cmd ExecuteNonQuery() 方法来执行 SQL 命令。
  15. 调用用户定义的方法将图像 ID 加载到组合框。(此方法稍后会解释,所以现在不用担心)
  16. 向用户显示保存成功的消息。
  17. 捕获上述代码执行过程中发生的任何错误。
  18. 最后,检查数据库连接是否已打开,如果已打开,则仅关闭连接。

下面演示了完整的选择和存储图像到数据库的代码。

SqlConnection con = new SqlConnection(DBHandler.GetConnectionString());
try
 {
   OpenFileDialog fop = new OpenFileDialog();
   fop.InitialDirectory = @"C:\"; 
   fop.Filter = "[JPG,JPEG]|*.jpg";
   if (fop.ShowDialog() == DialogResult.OK)
   {
     FileStream FS = new FileStream(@fop.FileName, FileMode.Open, FileAccess.Read);
     byte[] img = new byte[FS.Length];
     FS.Read(img, 0, Convert.ToInt32(FS.Length));

     if (con.State == ConnectionState.Closed)
       con.Open();
     SqlCommand cmd = new SqlCommand("SaveImage", con);
     cmd.CommandType = CommandType.StoredProcedure;
     cmd.Parameters.Add("@img", SqlDbType.Image).Value = img;
     cmd.ExecuteNonQuery();
     loadImageIDs();
     MessageBox.Show("Image Save Successfully!!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
   }
   else
   {
     MessageBox.Show("Please Select a Image to save!!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
   }

 }
 catch (Exception ex)
 {
   MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
 }
 finally
 {
   if (con.State == ConnectionState.Open)
     con.Close();
 }

 

检索和显示图像

在这里,我将逐步解释 btnDisplayImage 按钮的单击事件过程。

  1. 检查用户是否从组合框中选择了图像 ID。
  2. 检查图片框是否包含图像。
  3. 如果图片框中有图像,则清除该图像。
  4. 创建与数据库的连接。
  5. 通过传递存储过程名称和数据库连接来创建一个 SQL 命令对象 cmd
  6. cmd 对象的 CommandType 属性设置为存储过程类型。
  7. cmd 对象添加参数并为其设置值。
  8. 通过传递先前创建的 cmd 对象来创建一个 SQL 数据适配器对象 adp
  9. 创建一个数据表对象 dt 来保存 cmd 对象的结果。
  10. 检查与数据库的连接是否已关闭。
  11. 如果连接已关闭,则仅打开连接。
  12. 通过调用 adp 对象的 fill 方法,使用数据填充对象 dt
  13. 检查对象 dt 是否包含任何数据行。
  14. 通过传递图像的字节数组来创建一个内存流对象 ms
  15. 通过从内存流创建图像来设置图片框的 Image 属性。
  16. 将图片框的 SizeMode 属性设置为 Stretch。
  17. 调用图片框的 Refresh 方法。
  18. 捕获上述代码执行过程中发生的任何错误。
  19. 最后,检查数据库连接是否已打开,如果已打开,则仅关闭连接。

下面演示了完整的检索和显示图像的代码。

if (cmbImageID.SelectedValue != null)
{
    if (picImage.Image != null)
        picImage.Image.Dispose();

    SqlConnection con = new SqlConnection(DBHandler.GetConnectionString());
    SqlCommand cmd = new SqlCommand("ReadImage", con);
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.Parameters.Add("@imgId", SqlDbType.Int).Value = 
              Convert.ToInt32(cmbImageID.SelectedValue.ToString());
    SqlDataAdapter adp = new SqlDataAdapter(cmd);
    DataTable dt = new DataTable();
    try
    {
        if (con.State == ConnectionState.Closed)
            con.Open();
        adp.Fill(dt);
        if (dt.Rows.Count > 0)
        {
            MemoryStream ms = new MemoryStream((byte[])dt.Rows[0]["ImageData"]);
            picImage.Image = Image.FromStream(ms);
            picImage.SizeMode = PictureBoxSizeMode.StretchImage;
            picImage.Refresh();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", 
              MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        if (con.State == ConnectionState.Open)
            con.Close();
    }
}
else
{
    MessageBox.Show("Please Select a Image ID to Display!!", 
       "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

将所有图像 ID 加载到组合框

在此示例中,我使用了一个名为 loadImageIDs() 的通用方法,该方法的目的是将所有图像 ID 加载到组合框。将此过程写成单独的方法是因为我将在应用程序的多个地方使用它。提及这些地方。

  • btnRefresh 按钮的 Click 事件中。
  • btnLoadAndSave 按钮的 Click 事件中。
  • UsingSPs 窗体的 Load 事件中。

在这里,我将逐步解释 loadImageIDs() 用户定义方法的进程。

  1. 创建与数据库的连接。
  2. 通过传递存储过程名称和数据库连接来创建一个 SQL 命令对象 cmd
  3. cmd 对象的 CommandType 属性设置为存储过程类型。
  4. 通过传递先前创建的 cmd 对象来创建一个 SQL 数据适配器对象 adp
  5. 创建一个数据表对象 dt 来保存 cmd 对象的结果。
  6. 检查与数据库的连接是否已关闭。
  7. 如果连接已关闭,则仅打开连接。
  8. 通过调用 adp 对象的 fill 方法,使用数据填充对象 dt
  9. 检查对象 dt 是否包含任何数据行。
  10. cmbImageID 对象的 DataSource 属性设置为 dt 对象。
  11. cmbImageID 对象的值成员(ValueMember)属性设置为数据库表中的 ImageID 列。
  12. cmbImageID 对象的显示成员(DisplayMember)属性设置为数据库表中的 ImageID 列。
  13. cmbImageID 对象的 SelectedIndex 属性设置为值 0。
  14. 捕获上述代码执行过程中发生的任何错误。
  15. 最后,检查数据库连接是否已打开,如果已打开,则仅关闭连接。

下面演示了将所有图像 ID 加载到组合框的完整代码。

private void loadImageIDs()
{
    #region Load Image Ids
    SqlConnection con = new SqlConnection(DBHandler.GetConnectionString());
    SqlCommand cmd = new SqlCommand("ReadAllImageIDs", con);
    cmd.CommandType = CommandType.StoredProcedure;
    SqlDataAdapter adp = new SqlDataAdapter(cmd);
    DataTable dt = new DataTable();
    try
    {
        if (con.State == ConnectionState.Closed)
            con.Open();
        adp.Fill(dt);
        if (dt.Rows.Count > 0)
        {
            cmbImageID.DataSource = dt;
            cmbImageID.ValueMember = "ImageID";
            cmbImageID.DisplayMember = "ImageID";
            cmbImageID.SelectedIndex = 0;
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        if (con.State == ConnectionState.Open)
            con.Close();
    }
    #endregion
}

关注点

我希望这篇文章能帮助您理解和学习如何使用 C#.net 从 SQL Server 存储和检索图像。

我试图以简单的方式逐步解释整个过程。希望它能帮助您理解这篇文章。

如果您对本文有任何意见,请随时使用下方的评论和讨论区,因为您宝贵的想法将有助于我改进本文或撰写新文章。

历史

  • 2012 年 3 月 27 日:初稿
© . All rights reserved.