ADO.NET

数据库

数据库(DB,Database)简单来说就是数据的仓库,现实世界中仓库中有排货架(表),货物会分门别类的存放。仓库也分许多种类型,,如粮仓、弹药库等。同时仓库会有库管员(Database Administrator,DBA)对货物进行统一管理。当进货人或取货人(程序员)从仓库中取货时则需要凭证。

思考:为什么需要数据库呢?

文件存储的缺陷

例如:公司、学校的档案室

  • 计算机文件、文件操作
  • 开发人员需要熟悉操作磁盘文件的函数
  • 必须编写复杂的搜索算法才能高效的把数据从文件中检索出来
  • 当数据格式发生变化时,需要编写复杂的文件格式升级程序
  • 很难控制并发修改

数据库的特点

  • 海量存储
  • 查询速度快
  • 并发性问题控制
  • 安全性
  • 数据完整性,即保证在数据库中的数据是正确与真实的。

数据库管理系统

  • 数据库其实也是基于文件的
  • 对于数据不仅仅是需要存储,更重要的是将数据进行存储后怎样才能方便快捷的查询和操作。

日常所说的数据库,实际上指的是数据库管理软件,即数据库管理系统(DBMS,Database Management System)。如微软MS的SQLServer、大型Oracle和MySQ、IBM大型的DB2、MS文件的Access、极其轻量级的SQLite、Sybase等。除Access、SQLServerCE、SQLite等文件型数据库之外,部分数据库都需要数据库服务器才能运行。

SQLServer通常会有两种:MS的SQLServer、Sybase的SQLServer

不同品牌的数据库管理系统有着自己独特的优势,如MySQL速度快,适合对数据要求并不是非常严谨的应用场景。MSSQLServer与自家的.NET结合很好,但只能运行在Windows平台下,在大数据量、大交易量下表现得并不是十分好,但功能却比MySQL更加强大。

  • 前端NoSQL与后端关系型数据库结合,是处理大数据的典型方式。
  • 关系型数据库(RDB, Relationship Database)指的是存放一堆数据表的分类(Catagory)。

数据库相关

  • 数据库解决的问题:持久化存储、优化读写、保证数据的有效性。
  • 关系型数据库:基于实体关系(ER, Entity Relationship)模型、使用SQL语言进行操作
  • 数据库类型:文档型、服务型、关系型
  • 数据库设计
    • 三范式:列不可拆分、唯一标识、引用主键
    • 关系与存储:一对一、一对多、多对多

数据库概念

  • 数据库 DataBase:不同类的数据应存放在不同的数据库中
    • 便于各种数据类别进行个性化管理
    • 避免命名冲突
    • 安全性更高
  • Table:关系型数据库中的关系指的就是表,不同表根据存放的数据不同进行空间的优化,查找方便。
  • Column、字段Field、行/元祖Row
  • 用表格格式化数据:即便是引入自动识别设备也很容易识别
4933701-53a33377482e53a4.png

SQLServer

4933701-a6125382197fccb8.png
SQLServer
  1. 开启服务
  2. 登录方式及设置
  3. 添加账户
  4. 连接局域网中的数据库,启用TCP/IP协议。

SQLServer默认端口为1433

SQLServer表字段类型分为 int、bit、datatime、decimal、 char/varchar/nvarchar`

字符型中的n表示unicode编码,即每个字符占1个字节。
字符串没有n表示非unicode编码,英文或数字占1个字节,中文占2个字节。
字符串使用var表示可变长度,没有var表示不可变长度。若长度不够则末尾填补空格。
若选择int值时刻设置标识

约束

约束可实现数据的有效性检查,约束可分为主键、非空、唯一、默认、检查、外键...

4933701-e27d4474f084694c.png
唯一约束
4933701-0a94995ce92d2c90.png
默认约束

数据库脚本操作

  • 不区分大小写,字符串使用单引号,末尾无需添加分号。
  • 脚本按照功能分类
    DDL 数据定义语言,用于数据库对象创建,包括CREATE\ALTER\DROP
    DML 数据管理语言,用于对表数据的增删改查的操作,包括INSERT\UPDATE\DELETE\SELECT
    DCL 数据控制语言,用于权限分配 GRANT

数据库脚本注释

  • 单行注释 --
  • 多行注释 /**/

数据库定义

-- 选择数据库
USE TestDB;

-- 查看所有数据库
SELECT * FROM master.dbo.sysdatabases;

-- 创建数据库
CREATE DATABASE MyDB ON PRIMARY
(
    -- 主数据文件的逻辑名称
    NAME = "mydb_data",
    -- 主数据文件的物理名称
    FILENAME = "D:\SqlServerDB\mydb_data.mdf",
    -- 主数据文件的初始大小
    SIZE = 5MB,
    -- 主数据文件增长的最大值
    MAXSIZE = 100MB,
    -- 主数据文件的增长率
    FILEGROWTH = 15%
)
LOG ON
(
    -- 日志文件的逻辑名称
    NAME = "mydb_log",
    -- 日志文件的物理名称
    FILENAME = "D:\SqlServerDB\mydb_log.ldf",
    -- 日志文件的初始大小
    SIZE = 2MB,
    -- 日志文件的增长率
    FILEGROWTH = 1MB
);

查看自定义创建的所有表

-- 查询用户自定义的表
SELECT * FROM sysobjects WHERE xtype='U';
  • 主键约束 PRIMARY KEY
  • 非空约束 NOT NULL
  • 唯一约束 UNIQUE
  • 默认约束 DEFAULT
  • 检查约束 CHECK
  • 外键约束 FOREIGN KEY(列名) REFERENCES 表名(列名)

创建表

-- 玩家账户
DROP TABLE UserAccount;
CREATE TABLE UserAccount
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    UserID INT NOT NULL,
    UserName NVARCHAR(30) NOT NULL DEFAULT '',
    Password NCHAR(32) NOT NULL DEFAULT '',
    UserType SMALLINT NOT NULL DEFAULT 0,
    ChannelID INT NOT NULL DEFAULT 0,
    RegisterDate DATE NOT NULL DEFAULT CONVERT(NVARCHAR(12),GETDATE(),112),
    RegisterTime DATETIME NOT NULL DEFAULT GETDATE(),
    RegisterIP NCHAR(15) NOT NULL DEFAULT '0.0.0.0',
    LastLoginDate DATE NOT NULL,
    LastLoginTime DATETIME NOT NULL,
    LastLoginIP NCHAR(15) NOT NULL DEFAULT '0.0.0.0'
);
-- 玩家微信
DROP TABLE UserWechat;
CREATE TABLE UserWechat
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    UserID INT NOT NULL DEFAULT 0,
    OpenID NCHAR(32) NOT NULL DEFAULT '',
    UnionID NCHAR(32) NOT NULL DEFAULT '',
    NickName NVARCHAR(32) NOT NULL DEFAULT '',
    Sex SMALLINT NOT NULL DEFAULT 0,
    HeadImgUrl NVARCHAR(255) NOT NULL DEFAULT '',
    Country NVARCHAR(32) NOT NULL DEFAULT '',
    Province NVARCHAR(32) NOT NULL DEFAULT '',
    City NVARCHAR(32) NOT NULL DEFAULT ''
);
-- 玩家资料
DROP TABLE UserProfile;
CREATE TABLE UserProfile
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    UserID INT NOT NULL DEFAULT 0,
    RealName NVARCHAR(32) NOT NULL DEFAULT '',
    IdNumber NCHAR(18) NOT NULL DEFAULT '',
    Phone NCHAR(11) NOT NULL DEFAULT '',
    Email NVARCHAR(255) NOT NULL DEFAULT '',
    BankCard NCHAR(16) NOT NULL DEFAULT ''
);
-- 玩家登录
DROP TABLE UserLogin;
CREATE TABLE UserLogin
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    UserID INT NOT NULL DEFAULT 0,
    LoginTime DATETIME NOT NULL,
    LoginIP NCHAR(15) NOT NULL DEFAULT '0.0.0.0',
);
-- 玩家好友
DROP TABLE UserFriend;
CREATE TABLE UserFriend
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    UserID INT NOT NULL DEFAULT 0,
    FriendID INT NOT NULL DEFAULT 0
);

-- 游戏类型
DROP TABLE GameType;
CREATE TABLE GameType
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    TypeID INT NOT NULL DEFAULT 0,
    TypeKey NVARCHAR(32) NOT NULL DEFAULT '',
    TypeName NVARCHAR(32) NOT NULL DEFAULT '',
    PID INT NOT NULL DEFAULT 0,
    SortID INT NOT NULL DEFAULT 0,
    Enable BIT NOT NULL DEFAULT 1
);
-- 游戏区域
DROP TABLE GameArea;
CREATE TABLE GameArea
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    AreaID INT NOT NULL DEFAULT 0,
    AreaKey NVARCHAR(32) NOT NULL DEFAULT '',
    AreaName NVARCHAR(32) NOT NULL DEFAULT '',
    PID INT NOT NULL DEFAULT 0,
    SortID INT NOT NULL DEFAULT 0
);
-- 游戏种类
DROP TABLE GameKind;
CREATE TABLE GameKind
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    KindID INT NOT NULL DEFAULT 0,
    KindKey NVARCHAR(32) NOT NULL DEFAULT '',
    KindName NVARCHAR(32) NOT NULL DEFAULT '',
    TypeID INT NOT NULL DEFAULT 0,
    AreaID INT NOT NULL DEFAULT 0
);

-- 应用配置
DROP TABLE AppConfig;
CREATE TABLE AppConfig
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    AppID INT NOT NULL DEFAULT 0,
    AppName NVARCHAR(32) NOT NULL DEFAULT '',
);
-- 渠道配置
DROP TABLE ChannelConfig;
CREATE TABLE ChannelConfig
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    ChannelID INT NOT NULL DEFAULT 0,
    ChannelName NVARCHAR(32) NOT NULL DEFAULT '',
);
-- 道具配置
DROP TABLE PropConfig;
CREATE TABLE PropConfig
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    PropID INT NOT NULL DEFAULT 0,
    PropKey NVARCHAR(32) NOT NULL DEFAULT '',
    PropName NVARCHAR(32) NOT NULL DEFAULT '',
    PropUnit NVARCHAR(32) NOT NULL DEFAULT '',
    PropType NVARCHAR(32) NOT NULL DEFAULT '',
    PropDesc NVARCHAR(255) NOT NULL DEFAULT ''
);
-- 玩家道具
DROP TABLE UserProp;
CREATE TABLE UserProp
(
    ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    UserID INT NOT NULL DEFAULT 0,
    PropID INT NOT NULL DEFAULT 0,
    PropKey NVARCHAR(32) NOT NULL DEFAULT '',
    PropName NVARCHAR(32) NOT NULL DEFAULT '',
    PropCount INT NOT NULL DEFAULT 0,
);

删除数据

DELETE FROM [table_name] WHERE [condition]

清空数据

TRUNCATE TABLE [table_name]

说明:FROM关键字 可以省略不写, 通常实现分为逻辑删除和物理删除两种。

辅助命令
SET STATISTICS TIME ON/OFF 在消息栏显示详细执行时间
快捷键
CTRL + E 执行
CTRL + R 隐藏消息栏
CTRL +I 计划任务,对SQL语句进行分析。

ADO.NET

ADO.NET是一组类库,通过程序的方式访问数据库,类似System.IO下的类操作文件一样。System.Data类用来操作数据库,提供了统一的编程接口操作各种类型的数据库。

4933701-46019a2380dd6312.png
ADO.NET

ADO.NET组成

数据操作类 System.Data
DataTable
DataSet
DataRow
DataColumn
DataRelation
Constraint
DataColumnMapping
DataTableMapping

数据访问类的基类和接口 System.Data.Common

对SQL Server进行操作的数据访问类 System.Data.SqlClient
SqlConnection 数据库连接器
SqlCommandBuilder 数据库命名对象
SqlDataReader 数据读取器
SqlDataAdapter 数据适配器,用于填充DataSet。
SqlParameter 数据参数化,为存储过程定义参数。
SqlTransaction 数据库事务

ADO.NET 连接数据库

连接对象 Connection

Connection对象也称为数据库连接对象,Connection对象的功能是负责对数据源的连接,所有Connection对象对象的基类都是DbConnection类。

4933701-9f49d1c8dfbd4d80.png
Connection

连接字符串

基础语法:数据源DataSource + 数据库名称InitialCatalog+用户UserID+密码Password

# SQL Server数据库连接字符串 标准安全连接
Data Source=host;Initial Catalog=database;User Id=username;Passsword=password

数据库连接池

  • 两次连接所使用的字符串必须一样
  • 数据库打开后使用,使用完后会将连接对象放置到连接池中。但使用连接字符串...
  • 如果某个连接对象在使用中没有关闭,但又需要使用连接对象,则会重新...
  • 关闭连接池,在数据库连接字符串中设置Pooling=false

例如,在100次循环中执行数据库连接的打开和关闭,使用StopWatch
在ADO.NET中每个应用程序都会维护一个对象池,每次使用时不会重新建立对象,而是先从一个连接对象池获取,得到后直接使用。如果没有则创建,以减少每次新建的时间。

连接到数据库

Connection 对象有2个重要属性

  • ConnectionString 表示用于打开SQL Server数据库的字符串
  • State 表示 Connection的状态,有CloseOpen两种状态。

Connection 对象有2个重要方法

  • Open()方法指示打开数据库
  • Close()方法指示关闭数据库
string connectionString = "Data Source=.;Initial Catalog=TestDB;User Id=sa;Passsword=sa";
using(SqlConnection connction = new SqlConnection(connectionString))
{
  connction.Open();
}

数据提供程序常用类

  • Connect 连接数据库,和数据库建立网络连接。
  • Command 执行SQL语句,发送SQL给数据库引擎。
  • DataReader 只读只进的结果集,一条条读取数据。将数据库执行结果获取加载进入内存。
  • DataAdapter 封装以上3个对象
  • DataSet 数据集,临时数据库,断开式数据操作。

ADO.NET 访问数据库

  1. 使用Connection连接数据库
  2. 使用Command 执行SQL语句
  3. 执行SQL完毕后将结果一条条返回,使用DataReader加载到内存的DataSet中。

组合使用DataAdapterDataSet,其本质仍然是通过ConnectionCommandDataReader将数据全部读取出来后载入DataSet中。

连接数据库步骤

  1. 创建数据库连接字符串
    Data Source 表示数据源,即连接目标数据库实例。本机可以为点\localhost\机器名。
    Initial Catalog 初始化连接分类,即默认库。
    Integrated Security 身份验证方式,True表示使用Windows的身份验证方式。
  2. 创建连接对象
  3. 打开连接,打开连接成功则表示连接成功。
  4. 关闭连接释放资源
//局部变量
string password = string.Empty;

// todo 判断数据库服务是否开启

// 1.创建数据库连接
bool integrated_security = true;
string data_source = ".";
string initial_catalog = "Test";
string userid = "sa";
password = "jc520";

StringBuilder connectionString = new StringBuilder();
if (integrated_security == true)
{
    connectionString.AppendFormat("Data Source = {0}; Initial Catalog = {1}; Integrated Security = {2}", data_source, initial_catalog, integrated_security);
}
else
{
    connectionString.AppendFormat("Data Source = {0}; Initial Catalog = {1}; UserID = {2}; Password = {3}", data_source, initial_catalog, userid, password);
    //官方推荐
    //connectionString.AppendFormat("server = {0}; database = {1}; uid = {2}; pwd = {3}", data_source, initial_catalog, userid, password);
}
// 2.创建数据库连接对象
// 由于连接对象最后需要Close Dispose,所以简写为using。
// using相当编译时编译成为try...finally,并在finally中调用dispose()方法。
// Dispose()方法默认调用Close(),使用using可不编写。
using (SqlConnection connection = new SqlConnection(connectionString.ToString()))
{
    // 3. 打开连接
    // TODO 需捕获异常如数据库服务停止造成连接失败等情况
    //connection.Open();
    //Console.WriteLine("打开连接 创建连接成功");
    // 5. 插入数据
    string username = "admin";
    password = "admin";          
    string email = "junchow520@hotmail.com";
    StringBuilder sql = new StringBuilder();
    sql.AppendFormat("INSERT INTO Test.dbo.Users(UserName, Password, Email) VALUES('{0}', '{1}', '{2}')", username, password, email);
    // 6. 创建执行SQL语句命令对象 SqlCommand,由于也需要释放故使用using。
    using (SqlCommand command = new SqlCommand(sql.ToString(), connection))
    {
        //单独设置
        //command.CommandText = sql;
        //command.Connection = connection;

        // 7. 执行SQL语句
        // 最好的打开连接立刻执行SQL,即最晚打开连接,最早关闭连接,以节省资源。
        connection.Open();
        // 执行INSERT\UPDATE\DELETE时采用ExecuteNoQuery,此时会返回受影响行数,否则永远返回-1。
        // 执行返回单个结果(一行一列的单元格)时使用ExecuteScalar
        // 执行返回多个结果时使用ExcuteReader
        int effected_rows = command.ExecuteNonQuery();//返回受影响行数
        if(effected_rows > 0)
        {
            Console.WriteLine("添加成功,插入{0}行数据!", effected_rows);
        }

    }
    // 4. 关闭连接释放资源
    // connectionObject.Close();
}

数据库增删改操作

public static bool Execute()
{
    //数据库连接字符串
    string connectionString = "Data Source=JC-WIN10;Initial Catalog=Test;Integrated Security=True";
    //连接数据库
    using(SqlConnection connection = new SqlConnection(connectionString))
    {
        //SQL语句
        string sql = "";
        //操作数据库命令
        using(SqlCommand command = new SqlCommand(sql, connection))
        {
            //打开数据库
            connection.Open();
            //增删改
            int effectedRows = command.ExecuteNonQuery();
            if(effectedRows > 0)
            {
                return true;
            }

        }
    }
    return false;
}    

ADO.NET操作类与主要成员

  • Connection:Open()、Close()
  • Command:ExecuteNonQuery()、ExecuteScalar()、ExecuteReader()
  • DataReader:Read()、[]

参数化SQL语句

使用参数化方式,可有效防止SQL注入。

  • 使用Parameter的实现类SqlParameter
  • 使用Command的属性Parameters,其结果是一个参数集合。

封装SqlHelper静态工具类

SqlHelper是对常用数据库操作的代码封装,从可变的角度分析,那些操作时可变的代码那些操作是不可变的。注意的是,工具类一般都是静态类。

  • 每次操作时不变的代码:数据库连接字符串、向集合中存值、创建连接对象和命令对象、打开连接、执行命令
  • 每次操作时变化的代码:SQL语句
4933701-9d962fbea5b5a6d9.png
image.png

数据库连接字符串

$ vim Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="local" connectionString="server=.;database=Test;uid=sa;pwd=jc520"/>
  </connectionStrings>
</configuration>

封装类库

using System.Configuration;
using System.Data;
using System.Data.SqlClient;

namespace ADO
{
    /// <summary>
    /// 数据库SQL语句操作静态工具类
    /// </summary>
    public static partial class SqlHelper
    {
        /// <summary>
        /// 数据库连接字符串,从配置文件中获取。
        /// </summary>
        private static string connectionString = ConfigurationManager.ConnectionStrings["local"].ConnectionString;

        /// <summary>
        /// 执行SELECT查询返回多列
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="arr">可变参数数组</param>
        /// <returns></returns>
        public static SqlDataReader ExecuteReader(string sql, params SqlParameter[] param)
        {
            //创建连接
            SqlConnection connect = new SqlConnection(connectionString);
            //创建命令
            SqlCommand cmd = new SqlCommand(sql, connect);
            //添加参数
            if (param.Length > 0)
            {
                cmd.Parameters.AddRange(param);
            }
            //打开连接
            connect.Open();
            //执行查询,使用SqlDataReader时连接必须是打开的。
            //设置CommandBehavior.CloseConnection后,关闭SqlDataReader时会自动关闭使用的连接。
            return cmd.ExecuteReader(CommandBehavior.CloseConnection);
        }
        /// <summary>
        /// 执行SELECT查询返回首行首列
        /// </summary>
        /// <param name="sql">查询SQL语句</param>
        /// <param name="param">SQL语句的可变参数</param>
        /// <returns>对象</returns>
        public static object ExecuteScalar(string sql, params SqlParameter[] param)
        {
            using(SqlConnection connect = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand(sql, connect);
                cmd.Parameters.AddRange(param);
                connect.Open();
                return cmd.ExecuteScalar();
            }
        }      
        /// <summary>
        /// 执行非查询SQL语句
        /// </summary>
        /// <param name="sql">预计执行的非SELECT查询语句</param>
        /// <param name="param">SQL语句中的可变参数</param>
        /// <returns>影响行数</returns>
        public static int ExecuteNonQuery(string sql, params SqlParameter[] param)
        {
            using(SqlConnection connect = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand(sql, connect);
                cmd.Parameters.AddRange(param);
                connect.Open();
                return cmd.ExecuteNonQuery();
            }

        }
    }
}

测试操作

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

namespace ADO
{
    public class Test
    {
        static void Main(string[] args)
        {
            
            int UserID = 2;
            string sql = "SELECT UserName FROM [dbo].[Users] WHERE UserID = @UserID";
            SqlParameter param = new SqlParameter("@UserID", UserID);
            object username = SqlHelper.ExecuteScalar(sql, param);
            if(username == null)
            {
                Console.WriteLine("账户错误");
            }
            Log(username.ToString());
            Console.WriteLine(username.ToString());
            Console.ReadKey();
        }
        private static void Log(string message)
        {
            string msg = string.Format("[{0}] {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), message);

            string dirpath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            if (!Directory.Exists(dirpath))
            {
                Directory.CreateDirectory(dirpath);
            }

            string filepath = dirpath + DateTime.Now.ToString("yyyyMMdd") + ".log";
            using(StreamWriter writer = File.AppendText(filepath))
            {
                writer.WriteLine(msg);
            }
        }
    }
}

SQL与ADO

4933701-5f758fc2727755be.png
ADO.NET

连接池

  • 数据库连接池使应用程序能够重用池中的现有连接,而不是重复地创建对数据库的连接。
  • 数据库连接池极大地增加了应用程序的可扩展性,因为有限的数据库连接可以为更多的客户端提供服务。
  • 数据库连接池由于避免了用于建立连接的巨大时间开销因此可以提高性能
  • 根据连接字符串创建连接池,不同的连接字符串,产生不同的连接池。
  • 一个连接字符串对应一个连接池
  • SqlConnetion 对象只能被打开一次,在Close()后可以再进行Open()操作,在Dispose()之后就不能在Open()了。
4933701-f422097094ba86df.png
DataSet

DataSet 和 DataTable

4933701-e10721a54fd88509.png
数据集
4933701-2dd02a62a0d1ec89.png
数据集

数据适配器

4933701-331b119171afe8cf.png
ADO

SqlDataAdapter 数据库访问适配器

SqlDataAdapter是DataSet和SQLServer之间的桥接器,SqlDataAdapter通过对数据源使用适当的Transact-SQL语句映射Fill,它可填充DataSet中的数据以匹配数据源中的数据和Update(可更改数据源中的数据以匹配DataSet中的数据)来提供此桥接。当SqlDataAdapter填充DataSet时,它为返回的数据创建必须的表和列。

4933701-e03d2b41bbf23d15.png
DataAdapter

适配器模式:SqlServer表 => 适配器SqlDataAdapter => DataRow/DataTable

4933701-fa8e604b0c8af7c7.png
ADO.NET Data Access Interfaces
  • 填充方法 Fill()
  • 填充表格
  • 填充DataSet
  • Table表格遍历
  • SqlDataAdapterDataGridView配置实现CURD
  • SqlCommandBuilder辅助生成SqlCommand命令
4933701-f2f16756ad2399b9.png
数据集原理

SqlDataReader 与 SqlDataAdapter

  • SqlDataReader 基于连接,高效且只读访问,适合数据量较大。SqlDataAdapter 基于非连接,要求资源较大。
  • SqlDataReader 只能在保持跟数据库连接的状态下才可以读取,SqlDataAdapter 一次性读取一个表,然后填充到DataSet中,接着会断开数据库连接。
  • SqlDataReader 与 SqlDataAdapter 区别在于在线和离线的区别

SqlDataAdapter建立连接后,一次性把所有数据都加载到内存中,然后连接就关闭掉了。SqlDataReader建立连接后,一直保持连接状态,数据都在数据库中,只有用到哪个数据才会去取那个。

SqlDataAdapter 使用范例

4933701-6280306255c16e4a.png
范例
4933701-348c28768263070f.png
文件结构
  • 默认窗体为主窗体MainFrm,窗体文件一律以Frm结尾。
  • 窗体内添加DataGridView组件,命名为dgvUserInfo,其中dgv表示组件类型。
  • 使用Configuration.Manager读取配置文件App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="sql" connectionString="server=.;uid=sa;pwd=sasa;database=Test"/>
  </connectionStrings>
  <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
</configuration>
  • 创建视图模型
namespace WinFormApp
{
    class Users
    {
        public int UserID { get; internal set; }
        public string UserName { get; internal set; }
        public string NickName { get; internal set; }
    }
}

核心业务逻辑

// 从配置文件中读取数据库连接字符串
string connectionString = ConfigurationManager.ConnectionStrings["sql"].ConnectionString;
// 创建连接
using(SqlConnection sqlConnection = new SqlConnection(connectionString))
{
    string sql = "SELECT * FROM Users";
    // 创建适配器
    using(SqlDataAdapter adapter = new SqlDataAdapter(sql, sqlConnection))
    {
        // 创建内存表
        DataTable datatable = new DataTable();

        // 将数据库中的数据填充到内存表中,填充前无需打开数据库连接,数据适配器会自动打开连接并执行SQL。
        // Fill方法内部实现:
        // 1.先判断SqlConnection是否初始化,若无则打开连接。
        // 2.初始化一个SelectCommand对象
        // 3.通过cmd对象并执行,返回SqlDataReader对象。
        // 4.读取数据库中的数据,填充到DataTable中。
        adapter.Fill(datatable);

        // 将UserInfo表中数据加载到窗体DataGridView中
        //this.dgvUserInfo.DataSource = datatable;

        List<Users> datalist = new List<Users>();
        foreach (DataRow datarow in datatable.Rows)
        {
            datalist.Add(new Users()
            {
                UserID = int.Parse(datarow["UserID"].ToString()),
                UserName = datarow["UserName"].ToString(),
                NickName = datarow["NickName"].ToString()
            });
        };
        this.dgvUserInfo.DataSource = datalist;
    }
}

使用DataSet获取数据

string connectionString = ConfigurationManager.ConnectionStrings["sql"].ConnectionString;
string sql = "SELECT * FROM Users"; 
using (SqlDataAdapter adapter = new SqlDataAdapter(sql, connectionString))
{               
    DataSet dataset = new DataSet(); 
    adapter.Fill(dataset, "UserInfo");
    this.dgvUserInfo.DataSource = dataset.Tables["UserInfo"];  
}

https://www.bilibili.com/video/av31769371?p=6

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值