.NET基础 (20).NET中的数据库开发

ADO NET和数据库程序基础
1 什么是关系型数据库
2 如何通过SQL语句来实现行列转换
3 ADO NET支持哪几种数据源

ADO NET和数据库的连接
1 请简要叙述数据库连接池的机制
2 如何提高连接池内连接的重用率
3 一个连接字符串可以包含哪写属性
4 CommandBehavior.CloseConnection有何作用

使用ADO NET读写数据库
1 ADO NET支持哪两种方式来访问关系数据库
2 什么是强类型的DataSet
3 请解释SqlDataAdapter的基本工作机制
4 如何自动生成SqlDataAdapter的更新命令

ADO NET和数据库程序基础
1 什么是关系型数据库

关系型数据库是采用了关系模型来组织数据的数据库。关系模型就是指二维表模型。相对于其他模型来说,关系型数据库具有理解更容易、 使用更方便、维护更简单等优点。

2 如何通过SQL语句来实现行列转换

建表SQL:

 1 CREATE TABLE [dbo].[DepCount](
 2     [Id] [int] IDENTITY(1,1) NOT NULL,
 3     [Dep] [varchar](50) NULL,
 4     [Material] [varchar](50) NULL,
 5     [MCount] [int] NULL,
 6  CONSTRAINT [PK_DepCount] PRIMARY KEY CLUSTERED
 7 (
 8     [Id] ASC
 9 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
10 ) ON [PRIMARY]
11 GO
12 SET ANSI_PADDING OFF
13 GO
14 SET IDENTITY_INSERT [dbo].[DepCount] ON
15 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (1, N‘产房1‘, N‘材料1‘, 1)
16 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (2, N‘产房2‘, N‘材料2‘, 2)
17 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (3, N‘产房1‘, N‘材料3‘, 1)
18 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (4, N‘产房3‘, N‘材料3‘, 1)
19 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (5, N‘产房3‘, N‘材料1‘, 1)
20 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (6, N‘产房1‘, N‘材料1‘, 2)
21 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (7, N‘产房1‘, N‘材料2‘, 1)
22 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (8, N‘产房1‘, N‘材料3‘, 1)
23 INSERT [dbo].[DepCount] ([Id], [Dep], [Material], [MCount]) VALUES (9, N‘产品2‘, N‘材料3‘, 1)
24 SET IDENTITY_INSERT [dbo].[DepCount] OFF

写死的方法:

select Dep [部门],
SUM(case Material when ‘材料1‘ then Mcount else 0 end)[材料1],
SUM(case Material when ‘材料2‘ then Mcount else 0 end)[材料2],
SUM(case Material when ‘材料3‘ then Mcount else 0 end)[材料3]
from DepCount
group by Dep;

动态行列转换:

--申明一个字符串变量,以供动态拼装
declare @sql varchar(8000)
--拼装SQL命令
set @sql = ‘select Dep [部门]‘
--动态地获得材料,为每个材料构建一个列
select @sql = @sql + ‘,sum(case Material when ‘‘‘+Material+‘‘‘ then MCount else 0 end) [‘+Material+‘]‘
from (select distinct Material from DepCount) as a
--最终加上选择源和GROUP BY语句
select @sql = @sql+‘ from DepCount group by Dep‘
--执行SQL命令
exec(@sql)

动态语句可以根据实际材料种类来查找。

但是动态语句执行效率低,SQL命令长度根据实际表的内容变化,无法保证命令一定能运行。

3 ADO NET支持哪几种数据源

SQL Server 数据库、Oracle数据库、OLEDB提供商、ODBC提供商等

ADO NET和数据库的连接
1 请简要叙述数据库连接池的机制

数据库连接池,顾名思义就是一个存储数据库连接额缓冲池。由于连接和断开一个数据库的花销很大,反复连接和断开数据库的性能影响非常严重。而在.NET程序中,有时候无法预测下一次数据库访问的需求何时到来,所以通常的做法是,使用完一个连接后立即关闭它,这就需要ADO.NET的内部机制来维护这个访问池。连接池有选择地保留程序释放的数据库连接,以便以后使用。只要用户在连接上调用Open,池进程就会检查池中是否有可用的连接。如果某个池连接可用,会将该连接返回给调用者,而不是打开新连接。应用程序在该连接调用Close时,池进程会将连接返回到活动连接池中,而不是真正关闭连接。连接返回到池中后,即可在下一个Open调用中重复使用。

默认情况下,数据库连接池处于启用状态,但用户可以通过代码显示表明不使用数据库连接池。

using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=TestDatabase; Pooling=false"))
{
//不使用数据库连接池
connection.Open();
}

连接字符串中关于线程池的可选参数:


名    称


默 认 值


说    明


Connection Lifetime


0


当连接返回到池中时,将对它的创建时间和当前时间进行比较,如果时间间隔超过由Connection Lifetime指定的值(以秒为单位),则会毁坏该连接。在聚集配置中可以使用它来强制在运行服务器和刚联机的服务器之间达到负载平衡。如果值为0,则将使池连接具有最大的超时期限


Connection Reset


‘true‘


确定从池中移除数据库连接时是否将其重置。对于Microsoft SQL Server 7.0,如果设置为false,将避免在获取连接时经历一个额外的往返过程,但必须注意的是连接状态(如数据库上下文)不会被重置


Enlist


‘true‘


当为true时,如果存在事务上下文,池管理程序将自动在创建线程的当前事务上下文中登记连接


Max Pool Size


100


池中允许的最大连接数


Min Pool Size


0


池中维护的最小连接数


Pooling


‘true‘


当为true时,将从相应的池中取出连接,或者在必要时创建连接并将其添加到相应的池中

数据库连接池和线程池等其他缓冲池不同,由于数据源和连接参数选择的不同,每个数据库连接并不是完全通用的,ADO.NET通过连接字符串判断池内连接是否符合新的数据库连接需求。如果池中有相同字符串的连接,如果有则直接分配给用户,如果不存在就新建连接。

using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=TestDatabase"))
{
  //假设这是系统启动后的第一个数据库连接请求
  //一个新的连接将被建立
  connection.Open();
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=TestDatabase1"))
{
  //由于连接字符串和上一个连接不同,
  //保存在数据库连接池中的连接不能被使用
  connection.Open();
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=TestDatabase"))
{
  //连接字符串和第一个连接相同
  //保存在连接池中的第一个连接被使用
  connection.Open();
}

事实上,ADO.NET的组件本身并不直接包含连接池,而针对不同类别机制的数据源制定不同的连接池方案。对于SqlClient、OracleClient命名控件下的组件,使用的连接池是由托管代码直接编写的,可以理解为连接池直接在.NET框架中运行。而对于OLE DB和ODBC的数据源来说,连接池的实现完全依靠OLD DB和ODBC提供商实现,ADO.NET只与其约定相应规范。

2 如何提高连接池内连接的重用率

连接池重用率低下的原因

由于数据库连接池仅按照数据库连接字符串来判断连接是否可重用,所以连接字符串内的任何改动都会导致连接不能重用。而就系统内部而言,数据库连接字符串中最常被修改的两个属性就是数据库名和用户名/密码。对于使用多数据库的系统来说,只有同一数据库的连接才会被共用。而对于多用户的系统而言,只有同一用户的申请才能共用数据库连接。图9.4和图9.5展示了这两种情况。

如何提高数据库连接池重用率

在进行设计时,我们期望的最佳效果是连接池内的连接可以供所有用户重用,并且能够针对同一数据源内的不同数据库。对于实际系统来说,解决这两个问题通常意味着数据库中的额外工作,以及安全性方面的隐患。系统设计师在进行设计时,需要权衡利弊关系,根据实际情况来制定措施。下面提供一种能有效提供数据库连接池重用率,但会带来一点小安全隐患的方案。

同一数据库共享一个连接

同一用户共享一个连接

1)建立跳板数据库
在数据库内建立一个所有权限用户都能够访问的跳板数据库,在进行数据库连接时先连接到该数据库,然后再使用use"数据库名"这样的SQL语句来选择需要访问的数据库,这样就能够避免因为访问的数据库不一致而导致连接字符串不一致的情况,下面的代码演示了这一做法:

//这里使用"Entry"数据库作为跳板数据库
//然后再使用databaseName指定的数据库
SqlCommand cmd = new SqlCommand();
using (SqlConnection connection = new SqlConnection(
"Server=localhost;uid=xxx;pwd=xxx;database=Entry"))
{
    connection.Open();
    command.ExecuteNonQuery("USE " + databaseName);
}

2)不使用数据库用户系统来管理系统权限
这样做的结果是永远使用管理员的账号来连接数据库,而在做具体工作时再根据用户的实际权限,使用代码限定操作。带来的好处就是,数据库看连接字符串不会因为实际用户的不同而不同。下图展示了采用上述方案后数据库连接池的使用情况。

为了提高数据库连接池的重用率,唯一的方法就是尽量保证系统访问数据库所使用的连接字符串不变。例如建立跳板数据库,使所有连接都首先尝试访问跳板数据库。另外,统一使用超级用户账号可以进一步统一连接字符串,但这为系统带来了安全上的隐患。

3 一个连接字符串可以包含哪写属性

关 键 字 默 认 值 说    明
Application Name N/A 应用程序的名称,或者“.Net SqlClient Data Provider”(如果不提供应用程序名称)
Asynch ‘false‘ 如果设置为true,则启用异步操作支持。可识别的值为true、false、yes和no
AttachDBFilename N/A 主数据库文件的名称,包括可连接数据库的完整路径名。该路径可以是绝对路径,也可以是相对路径,这取决于是否使用DataDirectory替换字符串。如果使用DataDirectory,则对应的数据库文件必须存在于替换字符串指向的目录的子目录中。注意:远程服务器、HTTP及UNC路径名不受支持。必须按照如下方式使用关键字“database”(或其别名之一)指定数据库名称:"AttachDbFileName=|DataDirectory|\data\YourDB.mdf;integrated security=true;database=YourDatabase"
extended properties
Initial File Name
Connect Timeout 15 在终止尝试并产生错误之前,等待与服务器的连接的时间长度(以秒为单位)
Connection Timeout
Context Connection ‘false‘ 如果应对SQL Server进行进程内连接,则为true
Current Language N/A SQL Server语言记录名称
Data Source N/A 要连接的SQL Server实例的名称或网络地址。可以在服务器名称之后指定端口号:server=tcp:servername, portnumber。指定本地实例时,始终使用(local)。若要强制使用某个协议,请添加下列前缀之一:np:(local)、tcp:(local)或lpc:(local)
Server
Address
Addr
Network Address
Encrypt ‘false‘ 当该值为true时,如果服务器端安装了证书,则SQL Server将对所有在客户端和服务器之间传送的数据使用SSL加密。可识别的值为true、false、yes和no
Failover Partner N/A 在其中配置数据库镜像的故障转移合作伙伴服务器的名称。.NET Framework 1.0或1.1版不支持Failover Partner关键字
Initial Catalog N/A 数据库的名称
Database
Integrated Security ‘false‘ 当为false时,将在连接中指定用户ID和密码。当为true时,将使用当前的Windows账户凭据进行身份验证。可识别的值为true、false、yes、no以及与true等效的SSPI
Trusted_Connection
MultipleActiveResultSets ‘true‘ 如果为true,则应用程序可以维护多活动结果集(MARS)。如果为false,则应用程序必须在执行该连接上的任何其他批处理之前处理或取消一个批处理中的多个结果集。可识别的值为true和false。.NET Framework 1.0或1.1版不支持该关键字
Network Library Net ‘dbmssocn‘ 用于建立与SQL Server实例的连接的网络库。支持的值包括dbnmpntw(命名管道)、dbmsrpcn(多协议)、dbmsadsn(Apple Talk)、dbmsgnet(VIA)、dbmslpcn(共享内存)及dbmsspxn (IPX/SPX)和dbmssocn(TCP/IP)。相应的网络DLL必须安装在要连接的系统上。如果不指定网络而使用一个本地服务器(比如“.”或“(local)”),则使用共享内存
Packet Size 8192 用来与SQL Server的实例进行通信的网络数据包的大小,以字节为单位
Password- 或 -Pwd N/A SQL Server账户登录的密码。为保持高安全级别,可以使用Integrated Security或Trusted_Connection关键字
Persist Security Info ‘false‘ 当该值设置为false或no(强烈推荐)时,如果连接是打开的或者一直处于打开状态,那么安全敏感信息(如密码)将不会作为连接的一部分返回。重置连接字符串将重置包括密码在内的所有连接字符串值。可识别的值为true、false、yes和no
Replication ‘false‘ 如果使用连接来支持复制,则为true
TrustServerCertificate ‘false‘ 如果设置为true,则使用SSL对通道进行加密,但不通过证书链对可信度进行验证。如果将TrustServerCertificate设置为true并将Encrypt设置为false,则不对通道进行加密。可识别的值为true、false、yes和no
Type System Version N/A 指示应用程序期望的类型系统的字符串值。
可能的值有:Type System Version=SQL Server 2000;Type System Version=SQL Server 2005;Type System Version=Latest;如果设置为SQL Server 2000,将使用SQL Server 2000类型系统。
与SQL Server 2005实例连接时,执行下列转换:XML到NTEXT;UDT到VARBINARY;VARCHAR(MAX)、NVARCHAR(MAX)和VARBINARY(MAX)分别到TEXT、NEXT和IMAGE。
如果设置为SQL Server 2005,将使用SQL Server 2005类型系统。对ADO.NET的当前版本不进行任何转换。如果设置为Latest,将使用此客户端-服务器对无法处理的最新版本。这个最新版本将随着客户端和服务器组件的升级自动更新
User ID N/A SQL Server登录账户。为保持高安全级别,可以使用Integrated Security或Trusted_Connection关键字
User Instance ‘false‘ 一个值,用于指示是否将连接从默认的SQL Server速成版实例重定向到调用方账户下运行的运行时启动的实例
Workstation ID 本地计算机名称 连接到SQL Server的工作站的名称

4 CommandBehavior.CloseConnection有何作用

CommandBehavior.CloseConnection解决了流读取数据模式下,数据库连接不能有效关闭的情况。当某个XXXDataReader对象在生成时使用了CommandBehavior.CloseConnection,那数据库连接将在XXXDataReader对象关闭时自动关闭。

 1     partial class UseCommandBehavior
 2     {
 3         /// <summary>
 4         /// 测试方法
 5         /// </summary>
 6         /// <param name="args"></param>
 7         static void Main(string[] args)
 8         {
 9             //建立连接
10             SqlConnection con = new SqlConnection(conn_String);
11             try
12             {
13                 //测试使用了CommandBehavior.CloseConnection的方法
14                 Console.WriteLine("测试使用了CommandBehavior.CloseConnection的方法:");
15                 SqlDataReader sdr = GetReader_CloseConnection(con);
16                 while (sdr.Read()) { }
17                 sdr.Close();
18                 Console.WriteLine("读取完毕后的连接状态:" + con.State.ToString());
19                 //测试没有使用CommandBehavior.CloseConnection的方法
20                 Console.WriteLine("测试没有使用CommandBehavior.CloseConnection的方法:");
21                 SqlDataReader sdr1 = GetReader_NoCloseConnection(con);
22                 while (sdr1.Read()) { }
23                 sdr1.Close();
24                 Console.WriteLine("读取完毕后的连接状态:" + con.State.ToString());
25                 Console.Read();
26             }
27             finally
28             {
29                 //确保连接被关闭
30                 if (con.State != ConnectionState.Closed)
31                     con.Close();
32             }
33         }
34     }
35
36     partial class UseCommandBehavior
37     {
38         const String conn_String = "Server=localhost;Integrated Security=true;database=NetTest";
39         const String Sql = "select * from dbo.DepartCost";
40         /// <summary>
41         /// 使用CommandBehavior.CloseConnection
42         /// </summary>
43         /// <param name="con">为了测试需要,传入连接对象</param>
44         /// <returns></returns>
45         static SqlDataReader GetReader_CloseConnection(SqlConnection con)
46         {
47             try
48             {
49                 //打开连接,执行查询
50                 //并且返回SqlDataReader
51                 con.Open();
52                 SqlCommand cmd = con.CreateCommand();
53                 cmd.CommandText = Sql;
54                 SqlDataReader dr = cmd.ExecuteReader
55                                 (CommandBehavior.CloseConnection);
56                 return dr;
57             }
58             finally
59             {
60                 //因为使用了CommandBehavior.CloseConnection,
61                 //这里不需要关闭连接
62                 //con.Close();
63             }
64         }
65         /// <summary>
66         /// 不使用CommandBehavior.CloseConnection
67         /// </summary>
68         /// <param name="con">为了测试需要,传入连接对象</param>
69         /// <returns></returns>
70         static SqlDataReader GetReader_NoCloseConnection(SqlConnection con)
71         {
72             try
73             {
74                 //打开连接,执行查询
75                 //并且返回SqlDataReader
76                 con.Open();
77                 SqlCommand cmd = con.CreateCommand();
78                 cmd.CommandText = Sql;
79                 SqlDataReader dr = cmd.ExecuteReader();
80                 return dr;
81             }
82             finally
83             {
84                 //为了使返回的SqlDataReader可用,这里不能关闭连接
85                 //con.Close();
86             }
87         }
88     }

输出:

测试使用了CommandBehavior.CloseConnection的方法:
读取完毕后的连接状态:Closed
测试没有使用CommandBehavior.CloseConnection的方法:
读取完毕后的连接状态:Open

使用ADO NET读写数据库
1 ADO NET支持哪两种方式来访问关系数据库

连接式的访问

读取数据时保持和数据库的连接,并且在使用时独占整个连接,逐步地读取数据。这种模式较适合大数据量并且不能准确预测需要读取多少记录的情况。使用XXXCommand和XXXDataReader对象来读取数就是一个典型的连续式数据访问,这种模式的缺点是数据库连接较长时间地保持在打开状态。

示例:连接模式读取

  1     /// <summary>
  2     /// 数据访问层类型
  3     /// </summary>
  4     public class DataHelper
  5     {
  6         static readonly String conn_String ="Server=localhost;Integrated Security=true;database=NetTest";
  7         /// <summary>
  8         /// 使用给定的sql来访问数据库
  9         /// 返回SqlDataReader对象,提供连接式访问
 10         /// </summary>
 11         /// <param name="sql">SQL命令</param>
 12         /// <returns>SqlDataReader对象</returns>
 13         public static SqlDataReader GetReader(String sql)
 14         {
 15             SqlConnection con = new SqlConnection(conn_String);
 16             try
 17             {
 18                 //打开连接,执行查询
 19                 //并且返回SqlDataReader
 20                 con.Open();
 21                 using (SqlCommand cmd = con.CreateCommand())
 22                 {
 23                     cmd.CommandText = sql;
 24                     SqlDataReader dr = cmd.ExecuteReader
 25                                     (CommandBehavior.CloseConnection);
 26                     return dr;
 27                 }
 28             }
 29             //连接数据库随时可能发生异常
 30             catch (Exception ex)
 31             {
 32                 if (con.State != ConnectionState.Closed)
 33                     con.Close();
 34                 return null;
 35             }
 36         }
 37
 38     }
 39
 40     /// <summary>
 41     /// 使用数据库访问层
 42     /// 连接式读取数据
 43     /// </summary>
 44     class User
 45     {
 46         //SQL命令
 47         static readonly String sql = "select * from dbo.    /// <summary>
 48     /// 数据访问层类型
 49     /// </summary>
 50     public class DataHelper
 51     {
 52         static readonly String conn_String ="Server=localhost;Integrated Security=true;database=NetTest";
 53         /// <summary>
 54         /// 使用给定的sql来访问数据库
 55         /// 返回SqlDataReader对象,提供连接式访问
 56         /// </summary>
 57         /// <param name="sql">SQL命令</param>
 58         /// <returns>SqlDataReader对象</returns>
 59         public static SqlDataReader GetReader(String sql)
 60         {
 61             SqlConnection con = new SqlConnection(conn_String);
 62             try
 63             {
 64                 //打开连接,执行查询
 65                 //并且返回SqlDataReader
 66                 con.Open();
 67                 using (SqlCommand cmd = con.CreateCommand())
 68                 {
 69                     cmd.CommandText = sql;
 70                     SqlDataReader dr = cmd.ExecuteReader
 71                                     (CommandBehavior.CloseConnection);
 72                     return dr;
 73                 }
 74             }
 75             //连接数据库随时可能发生异常
 76             catch (Exception ex)
 77             {
 78                 if (con.State != ConnectionState.Closed)
 79                     con.Close();
 80                 return null;
 81             }
 82         }
 83
 84     }
 85
 86     /// <summary>
 87     /// 使用数据库访问层
 88     /// 连接式读取数据
 89     /// </summary>
 90     class User
 91     {
 92         //SQL命令
 93         static readonly String sql = "select * from dbo.DepartCost";
 94         static void Main(string[] args)
 95         {
 96             //使用连接式方法读取数据源
 97             using (SqlDataReader reader = DataHelper.GetReader(sql))
 98             {
 99                 //得到列数
100                 int colcount = reader.FieldCount;
101                 //打印列名
102                 for (int i = 0; i < colcount; i++)
103                 {
104                     Console.Write("{0}  ", reader.GetName(i));
105                 }
106                 Console.Write("\r\n");
107                 //顺序读取每一行,并打印
108                 while (reader.Read())
109                 {
110                     for (int i = 0; i < colcount; i++)
111                     {
112                         Console.Write("{0}  ", reader[i].ToString());
113                     }
114                     Console.Write("\r\n");
115                 }
116                 reader.Close();
117             }
118             Console.Read();
119         }
120     }";
121         static void Main(string[] args)
122         {
123             //使用连接式方法读取数据源
124             using (SqlDataReader reader = DataHelper.GetReader(sql))
125             {
126                 //得到列数
127                 int colcount = reader.FieldCount;
128                 //打印列名
129                 for (int i = 0; i < colcount; i++)
130                 {
131                     Console.Write("{0}  ", reader.GetName(i));
132                 }
133                 Console.Write("\r\n");
134                 //顺序读取每一行,并打印
135                 while (reader.Read())
136                 {
137                     for (int i = 0; i < colcount; i++)
138                     {
139                         Console.Write("{0}  ", reader[i].ToString());
140                     }
141                     Console.Write("\r\n");
142                 }
143                 reader.Close();
144             }
145             Console.Read();
146         }
147     }

脱机式的访问

脱机式访问并不是指不连接数据库,而是指一般在读取实际数据时连接已经断开。脱机式访问在连接至数据库后,会根据SQL命令批量读入所有记录,这样就直接断开数据库连接以供其他线程使用,读入的记录暂时存放自内存中。脱机访问的优点在于不会长期占用数据库连接资源,而这样做的代价就是将消耗内存俩存储数据,在大数据查询的情况下该方式并不适合。使用XXXDataAdapter和DataSet对象就是最常用的脱机访问方式,下列代码展示了其使用方法。

 1     /// <summary>
 2     /// 数据访问层类型
 3     /// </summary>
 4     public class DataHelper
 5     {
 6         static readonly String conn_String = "Server=localhost;Integrated Security=true;database=NetTest";
 7         /// <summary>
 8         /// 使用给定的sql来访问数据库
 9         /// 返回DataSet对象
10         /// </summary>
11         /// <param name="sql">SQL命令</param>
12         /// <returns>DataSet对象</returns>
13         public static DataSet GetDataSet(String sql)
14         {
15             SqlConnection con = new SqlConnection(conn_String);
16             DataSet ds = new DataSet();
17             try
18             {
19                 //打开连接,执行查询
20                 //并且返回DataSet
21                 con.Open();
22                 using (SqlDataAdapter sd = new SqlDataAdapter(sql, con))
23                 {
24                     //这里数据将被批量读入
25                     sd.Fill(ds);
26                 }
27                 return ds;
28             }
29             //连接数据库随时可能发生异常
30             catch (Exception ex)
31             {
32                 if (con.State != ConnectionState.Closed)
33                     con.Close();
34                 return ds;
35             }
36         }
37     }
38
39     /// <summary>
40     /// 使用数据库访问层
41     /// 脱机式读取数据
42     /// </summary>
43     class User
44     {
45         //SQL命令
46         static readonly String sql = "select * from dbo.DepCount";
47         static void Main(string[] args)
48         {
49             DataSet ds = DataHelper.GetDataSet(sql);
50             //打印结果,这里假设只对DataSet中的第一个表感兴趣
51             DataTable dt = ds.Tables[0];
52             //打印列名
53             foreach (DataColumn column in dt.Columns)
54                 Console.Write("{0}  ", column.ColumnName);
55             Console.Write("\r\n");
56             //打印表
57             foreach (DataRow row in dt.Rows)
58             {
59                 for (int i = 0; i < dt.Columns.Count; i++)
60                 {
61                     Console.Write("{0}  ", row[i].ToString());
62                 }
63                 Console.Write("\r\n");
64             }
65             Console.Read();
66         }
67     }

2 什么是强类型的DataSet

指那些固定结构的继承自DataSet的类型,相比于DataSet而言,强类型的DataSet具有访问方便、约束性强的特点,有利于数据访问层的隔离,也有利于把错误提前到编译阶段发现。

3 请解释SqlDataAdapter的基本工作机制

SqlDataAdapter使用内部4个SQLCommand类型的成员进行检索和更新操作,分别是SelectCommand、InsertCommand、UpdateCommand和DeleteCommand。SelectCommand成员可以在SqlDataAdapter构造时被构造,程序员可以手动地设置这4个成员来控制SqlDataAdapter的行为。

4 如何自动生成SqlDataAdapter的更新命令

使用SQLCommandBuilder类型和自动生成SQLDataAdapter中的更新命令。

建议,尽量手动地构造更新Command对象,而避免使用XXXCommandBuilder类型。实际工作中很少用DataAdapter来执行增、删、改的操作,要执行这些操作直接拼SQL或者调用存储过程,用SqlCommand.ExecuteNonQuery执行就行了。

转载请注明出处:

作者:JesseLZJ
出处:http://jesselzj.cnblogs.com

时间: 2024-11-06 22:53:24

.NET基础 (20).NET中的数据库开发的相关文章

摘录-IT企业必读的200个.NET面试题-09 .NET中的数据库开发

ADO.NET和数据库的连接 Q: 请简要叙述数据库连接池的机制 数据库连接池就是一个存储数据库连接的缓冲池.ADO.NET对上层用户提供了数据库连接池的服务,使用完的数据库连接将被有选择地保持在数据库连接池中,以供下次使用.当用户以某个连接字符串申请数据库连接时,数据库连接池将尝试在池中寻找具有相同连接字符串的连接,并直接提供给用户. Q: 如何提高连接池内连接的重用率 为了提高数据库连接池的重用率,唯一的方法就是尽量保证系统访问数据库所使用的连接字符串不变.例如统一使用超级用户账户可以进一步

htML+CSS3-》第3阶段:HTML5之CSS3基础与加强 中

HTML+CSS3->第3阶段:HTML5之CSS3基础与加强中 60前端开发基础视频-复合选择器之子元素选择器 子元素选择器,是让css选择器智能选择子辈的元素. 例如:h1>strong{color:red;} 解读为:选择器h1>strong可以解释为"选择作为h1元素子元素的所有strong元素". 61前端开发基础视频-属性选择器 属性选择器 <!DOCTYPE html> <html lang="zh"> <

爆栈三部曲:数据库开发大系技术栈 (300多技术点)

前言 这个数据库技术栈是我写的“爆栈三部曲”的最后一部 ;-) 最近我写过  .NET技术大系概览 (迄今为止最全的.NET技术栈) ,相信很多网友感叹掌握的.NET技术远没有这个技术栈里面所描述的多. 然后我还写 Web前端开发大系概览 (前端开发技术栈) ,包含大约180个技术点,做前端的都会觉得前端开发包含的技术相对繁多. 什么叫全栈(full stack)?简单地说就是万金油,web前端.后台.数据库.桌面应用等都能搞. 爆栈(stack overflow)来得更多些,包括但不仅限于:

.NET基础拾遗(6)ADO.NET与数据库开发基础

一.ADO.NET和数据库程序基础 1.1 安身立命之基本:SQL SQL语句时操作关系型数据库的基础,在开发数据访问层.调试系统等工作中十分常用,掌握SQL对于每一个程序员(无论是.NET.Java还是C++等)都非常重要.这里挑选了一个常见的面试题目,来热热身. 常见场景:通过SQL实现单表行列转换 行列转换时数据库系统中经常遇到的一个需求,在数据库设计时,为了适合数据的累积存储,往往采用直接记录的方式,而在展示数据时,则希望整理所有记录并且转置显示.下图是一个行列转换的示意图: ①好了,废

IOS开发UI基础—在UIImageView中添加按钮以及Tag的参数说明

ios开发UI基础-在ImageView中添加按钮以及Tag的参数说明 一.tag参数 一个视图通常都只有一个父视图,多个子视图,在开发中可以通过使用子视图的tag来取出对应的子视图.方法为Viewwithtag: 提示点:在xib中如果想要通过tag参数获取对应的控件(属性),不要把tag的参数设置为0,因为xib中所有的对象默认tag都为0,设置为0取不到对象. 二.ImageView中添加按钮(1)ImageView和Button的比较 Button按钮的内部可以放置多张图片(4),而Im

第20课-数据库开发及ado.net 可空值类型,资料管理器,多条件查询,Case

第20课-数据库开发及ado.net 可空值类型,资料管理器,多条件查询,Case SqlHelper using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Text; namespace _02省市联动 { public static  class SqlHelper { //

数据库开发——参照完整性——在外键中使用Delete on cascade选项

原文:数据库开发--参照完整性--在外键中使用Delete on cascade选项 原文: http://www.mssqltips.com/sqlservertip/2743/using-delete-cascade-option-for-foreign-keys/?utm_source=dailynewsletter&utm_medium=email&utm_content=headline&utm_campaign=2012731 参照完整性在设计数据库时需要重视,在我作为

android开发中的数据库SQLite的使用

其实学习android很久了,关于数据存储,之前学习的时候也一同学习过,编程这些东西很久没用都忘得差不多了,最近做个项目要用到,所以又学习了一遍. android中关于数据的存储有好几种,这次主要是SQLite的使用. 首先说一点,我的技术很烂,原理什么的不说了,就是讲一下怎么使用,包括“增删改查”这几个操作. 使用数据库的前提是有数据库,有表,所以我们首先是要有一个数据库,然后还得建一张表(至少一张表).sql语句就是“create table XXX()”.作为一个数据库系统,SQLite也

AndoridSQLite数据库开发基础教程(10)

AndoridSQLite数据库开发基础教程(10) 添加触发器 触发器(TRIGGER)是由事件来触发某个操作.这些事件包括INSERT.DELETE.UPDATE和UPDATE OF.当数据库系统执行这些事件时,会激活触发其执行相应的操作.下面为数据库添加触发器.操作步骤如下: (1)打开的数据库,单击左下角的齿轮按钮,选择其中的Create Trigger选项,弹出Trigger Creator对话框,如图1.23所示. 图1.23  Trigger Creator对话框 (2)在Trig