ADO.NET 面试问题:第 2 部分






3.36/5 (17投票s)
ADO.NET 面试问题:第 2 部分。
问题
- (B) 如何在 ADO.NET 中使用存储过程以及如何向存储过程提供参数?
- (B) 如何强制在数据读取器关闭后关闭连接对象?
- (B) 我想强制数据读取器只返回数据存储的架构而不是数据。
- (B) 当我们期望返回单行时,如何微调 Command 对象?
- (B) DataSet 对象提供了哪些用于生成 XML 的方法?
- (B) 如何保存 DataSet 中的所有数据?
- (B) 如何检查 DataSet 自加载以来是否发生了更改?
- (B) 如何在 DataSet 的 DataTable 对象中添加/删除行?
- (B) DataView 的基本用途是什么?
- (B) "DataSet" 和 "DataReader" 之间有什么区别?
- (B) 如何在 DataSet 中加载多个表?
- (B) 如何在 DataSet 中的表之间添加关系?
- (B) Command Builder 的用途是什么?
- (B) "乐观锁定" 和 "悲观锁定" 之间有什么区别?
- (A) 在 ADO.NET 中有多少种实现锁定的方法?
- (A) 如何在 .NET 中执行事务?
- (I) DataSet.Clone 和 DataSet.Copy 之间有什么区别?
- (A) 您能解释一下 ADO.NET DataSet 和 ADO Recordset 之间的区别吗?
- (A) 详细解释连接池的基础知识。
- (A) ADO.NET 连接字符串中的最大连接池大小是多少?
- (A) 如何启用和禁用连接池?
- (I) ADO.NET 2.0 有哪些额外功能?
引言
在本节中,我们将讨论 ADO.NET 中的一个重要概念。您可以从以下地址下载我的 .NET 面试问题 PDF:http://www.questpond.com/SampleDotNetInterviewQuestionBook.zip。
我的架构师面试问题系列的前几部分
- 第一部分 - SoftArchInter1.aspx
- 第二部分 - SoftArch2.aspx
- 第三部分 - SoftArch3.aspx
- 第四部分 - SoftArch4.aspx
UML 面试问题 第 1 部分:SoftArch5.aspx
祝您求职愉快......
(B) 如何在 ADO.NET 中使用存储过程以及如何向存储过程提供参数?
ADO.NET 提供了 SqlCommand
对象,该对象提供了执行存储过程的功能。
注意:示例代码位于文件夹 WindowsSqlClientCommand 中。在为上一个问题创建的相同数据库 "Employees" 中创建了两个存储过程。
CREATE PROCEDURE SelectByEmployee @FirstName nvarchar(200) AS
Select FirstName from Employees where FirstName like @FirstName + '%'
CREATE PROCEDURE SelectEmployee AS
Select FirstName from Employees
If txtEmployeeName.Text.Length = 0 Then
objCommand = New SqlCommand("SelectEmployee")
Else
objCommand = New SqlCommand("SelectByEmployee")
objCommand.Parameters.Add("@FirstName", Data.SqlDbType.NVarChar, 200)
objCommand.Parameters.Item("@FirstName").Value = txtEmployeeName.Text.Trim()
End If
在上述示例中,没有太大变化,只是将 SQL 移到了存储过程中。有两个存储过程:"Select Employee" 选择所有员工,"SelectByEmployee" 返回以特定字符开头的员工姓名。如您所见,为了向存储过程提供参数,我们正在使用 Command 对象的参数对象。在这样的问题中,面试官期望两个简单的答案:一是我们使用 Command 对象执行存储过程,二是使用参数对象向存储过程提供参数。上述示例仅用于实际感受。简短、友好、获得工作。
(B) 如何强制在数据读取器关闭后关闭连接对象?
Command 方法 ExecuteReader
接受一个名为 CommandBehavior
的参数,我们可以在其中指定在数据读取器关闭后自动关闭连接。
PobjDataReader = pobjCommand.ExecuteReader (CommandBehavior.CloseConnection)
(B) 我想强制数据读取器只返回数据存储的架构而不是数据。
PobjDataReader = pobjCommand.ExecuteReader (CommandBehavior.SchemaOnly)
(B) 当我们期望返回单行时,如何微调 Command 对象?
同样,CommandBehaviour
枚举提供了两个值:SingleResult
和 SingleRow
。如果您期望单个值,则传递 CommandBehaviour.SingleResult
,查询会相应地进行优化;如果您期望单行,则传递 CommandBehaviour.SingleRow
,查询会根据单行进行优化。
(B) 在 .NET 项目中存储连接字符串的最佳位置是哪里?
配置文件是存储连接字符串的最佳选择。如果是基于 Web 的应用程序,将使用 Web.config 文件;如果是 Windows 应用程序,则使用 App.config 文件。
(B) 填充数据集涉及哪些步骤?
变体问题:如何使用数据适配器填充数据集?
示例代码位于 WindowsDataSetSample 文件夹中。LoadData
包含了连接和加载到数据集的所有实现。此数据集最终绑定到 ListBox
。以下是示例代码:
Private Sub LoadData()
Dim strConnectionString As String
strConnectionString = AppSettings.Item("ConnectionString")
Dim objConn As New SqlConnection(strConnectionString)
objConn.Open()
Dim objCommand As New SqlCommand("Select FirstName from Employees")
objCommand.Connection = objConn
Dim objDataAdapter As New SqlDataAdapter()
objDataAdapter.SelectCommand = objCommand
Dim objDataSet As New DataSet
End Sub
在这些类型的问题中,面试官从实践角度出发,看您是否使用过数据集和数据适配器。让我先解释上面的代码,然后我们将讨论面试时应该解释哪些步骤。
Dim objConn As New SqlConnection(strConnectionString)
objConn.Open()
第一步是打开连接。再次注意,连接字符串是从配置文件中加载的。
Dim objCommand As New SqlCommand("Select FirstName from Employees")
objCommand.Connection = objConn
第二步是使用适当的 SQL 创建 Command 对象,并将连接对象设置为此命令。
Dim objDataAdapter As New SqlDataAdapter()
objDataAdapter.SelectCommand = objCommand
第三步是创建 Adapter 对象,并将 Command 对象传递给 Adapter 对象。
objDataAdapter.Fill(objDataSet)
第四步是使用数据适配器的 Fill 方法加载数据集。
lstData.DataSource = objDataSet.Tables(0).DefaultView
lstData.DisplayMember = "FirstName"
lstData.ValueMember = "FirstName"
第五步是将加载的数据集与 GUI 绑定。此时,示例中有一个列表框作为 UI。UI 的绑定是通过使用数据集的默认视图完成的。回顾一下,每个数据集都有表,每个表都有视图。在这个示例中,我们只加载了一个表,即 Employees 表,因此我们使用索引零来引用它。在面试中解释所有五个步骤,您会看到面试官脸上露出笑容,并且聘用书就在您手中。
(B) 数据集对象提供了哪些用于生成 XML 的方法?
注意:XML 是经典 ADO 和 ADO.NET 之间最重要的飞跃之一。因此,这个问题通常更广泛地被问及如何将任何数据转换为 XML 格式。最好的答案是使用以下方法:
ReadXML
:将 XML 文档读入 DataSet。GetXML
:这是一个返回包含 XML 文档的字符串的函数。Writexml
:将 XML 数据写入磁盘。
(B) 如何保存数据集中的所有数据?
DataSet 具有 AcceptChanges
方法,该方法提交自上次执行以来的所有更改。
注意:本文没有任何 AcceptChanges
的示例。我将其作为家庭作业示例留给读者。但就面试而言,这已经足够了。
(B) 如何检查 DataSet 自加载以来是否发生了更改?
变体问题:如何取消对 DataSet 所做的所有更改?
变体问题:如何获取 DataSet 中已更改的值?
为了跟踪更改,DataSet 有两个方法可以提供帮助:GetChanges
和 HasChanges
。GetChanges
返回自加载或执行 AcceptChanges
以来已更改的数据集。HasChanges
指示自加载数据集或执行 AcceptChanges
方法以来是否已进行任何更改。要放弃自加载数据集以来的所有更改,请使用 RejectChanges
。注意:关于这些属性最容易被误解的一点是,它们跟踪实际数据库中的更改。这是一个根本性的错误;实际上,它们与数据集的更改有关,与实际数据库中发生的更改无关。数据集是断开连接的,对实际数据库中发生的更改一无所知。
(B) 如何在 DataSet 的 DataTable 对象中添加/删除行?
DataTable
提供了 NewRow
方法来向 DataTable
添加新行。DataTable
有一个 DataRowCollection
对象,其中包含 DataTable
对象中的所有行。以下是 DataRowCollection
对象提供的方法:
Add
:在DataTable
中添加新行Remove
:从DataTable
中删除DataRow
对象RemoveAt
:根据DataTable
的索引位置从DataTable
中删除DataRow
对象
(B) DataView 的基本用途是什么?
DataView
表示一个完整的表,也可以是根据某些条件的一小部分行。它最适合用于在数据表中排序和查找数据。DataView
具有以下方法:
Find
:它接受一个值数组并返回行的索引。FindRow
:这也接受一个值数组,但返回DataRow
的集合。如果我们要操作DataTable
对象的数据,则创建DataTable
对象的 DataView(使用 "Default View",我们可以创建一个DataView
对象)。AddNew
:向DataView
对象添加新行。Delete
:从DataView
对象中删除指定的行。
(B) "DataSet" 和 "DataReader" 之间有什么区别?
变体问题:为什么 DataSet 比 DataReader 慢?第四点是变体问题的答案。
注意:这是我最好的问题,我们期望每个人都能回答。它几乎在所有公司中都被问到 99%....基本,非常基本,记住它。
DataSet 和 DataReader 之间的主要区别如下:
- DataSet 是一种断开连接的架构,而 DataReader 在读取数据时具有实时连接。如果我们要缓存数据并传递到不同的层,DataSet 是最佳选择,并且它具有良好的 XML 支持。
- 当应用程序需要从多个表中访问数据时,DataSet 是最佳选择。
- 如果我们在读取记录时需要向后移动,DataReader 不支持此功能。
- 然而,DataSet 的最大缺点之一是速度。由于 DataSet 包含相当大的开销,例如关系、多个表等,因此速度比 DataReader 慢。尽可能使用 DataReader,因为它专门用于性能。
(B) 如何在 DataSet 中加载多个表?
objCommand.CommandText = "Table1"
objDataAdapter.Fill(objDataSet, "Table1")
objCommand.CommandText = "Table2"
objDataAdapter.Fill(objDataSet, "Table2")
上面是一个示例代码,展示了如何在单个 DataSet 对象中加载多个 DataTable 对象。示例代码显示了对象 ObjDataSet
中的两个表 Table1 和 Table2。
lstdata.DataSource = objDataSet.Tables("Table1").DefaultView
为了引用 Table1
DataTable,请使用 DataSet 的 Tables
集合,DefaultView
对象将为您提供必要的输出。
(B) 如何在 DataSet 中的表之间添加关系?
Dim objRelation As DataRelation
objRelation=New DataRelation("CustomerAddresses", _
objDataSet.Tables("Customer").Columns("Custid"),_
objDataSet.Tables("Addresses").Columns("Custid_fk"))
objDataSet.Relations.Add(objRelation)
可以使用 DataRelation
对象在 DataTable 对象之间添加关系。上面的示例代码正在尝试使用 CustomerAddresses
DataRelation 对象在 Customer
和 Addresses
DataTables 之间建立关系。
(B) CommandBuilder 的用途是什么?
CommandBuilder 自动构建 "Parameter" 对象。下面是一个使用 CommandBuilder 加载其参数对象的简单代码:
Dim pobjCommandBuilder As New OleDbCommandBuilder(pobjDataAdapter)
pobjCommandBuilder.DeriveParameters(pobjCommand)
使用 DeriveParameters
方法时要小心,因为它需要额外访问数据存储,这可能会非常低效。
(B) 乐观锁定和悲观锁定有什么区别?
在悲观锁定中,当用户想要更新数据时,它会锁定记录,然后没有人可以更新数据。其他用户只能在悲观锁定存在时查看数据。在乐观锁定中,多个用户可以打开同一条记录进行更新,从而最大程度地增加并发性。记录只在更新时才被锁定。这是实际操作中最优选的锁定方式。如今,在基于浏览器的应用程序中,这非常常见,而悲观锁定不是一种实用的解决方案。
(A) 在 ADO.NET 中有多少种实现锁定的方法?
以下是使用 ADO.NET 实现锁定的方法:
Update table1 set field1=@test where Last Timestamp=@Current Timestamp
Update table1 set field1=@test where field1 = @oldfield1value
锁定可以在 ADO.NET 端处理,也可以在 SQL Server 端处理,即在存储过程中。有关如何在 SQL Server 中实现锁定的更多详细信息,请阅读 SQL Server 文章中的“SQL Server 中有哪些不同的锁?”。
- 当我们调用 DataAdapter 的
Update
方法时,它会在内部处理锁定。如果 DataSet 值与数据库中的当前数据不匹配,它会引发并发异常错误。我们可以使用Try. Catch
块轻松捕获此错误,并向用户显示适当的错误消息。 - 在表中定义一个 DateTime 戳字段。当您实际执行
UPDATE
SQL 语句时,将当前时间戳与数据库中的现有时间戳进行比较。下面是一个示例 SQL,它在更新之前检查时间戳,如果时间戳不匹配,它将不更新记录。这是行业用于锁定的最佳实践。 - 检查 SQL Server 中存储的原始值和实际更改的值。在存储过程中,在更新之前检查旧数据是否与当前示例相同。在下面显示的 SQL 中,在更新
field1
之前,我们检查旧的field1
值是否相同。如果不同,则表示其他人已更新,必须采取必要的措施。
(A) 如何在 .NET 中执行事务?
开发事务应用程序时最常见的步骤序列如下:
- 使用 Connection 对象的
Open
方法打开数据库连接。 - 使用 Connection 对象的
BeginTransaction
方法开始一个事务。此方法为我们提供一个事务对象,我们稍后将使用它来提交或回滚事务。请注意,在调用BeginTransaction
方法之前执行的任何查询所导致的更改将在它们执行后立即提交到数据库。将 Command 对象的Transaction
属性设置为上述事务对象。 - 使用 Command 对象执行 SQL 命令。我们可以为此目的使用一个或多个 Command 对象,只要所有对象的
Transaction
属性都设置为有效的事务对象。 - 使用事务对象的
Commit
或Rollback
方法提交或回滚事务。 - 关闭数据库连接。
(I) DataSet.Clone 和 DataSet.Copy 之间有什么区别?
- Clone:它只复制结构,不复制数据。
- Copy:复制结构和数据。
(A) 您能解释一下 ADO.NET DataSet 和 ADO Recordset 之间的区别吗?
记录集和数据集之间有两个主要的基本区别:
- 使用数据集,您可以从两个数据库(如 Oracle 和 SQL Server)中检索数据并将它们合并到一个数据集中,使用记录集则不可能。
- 所有 DataSet 表示都使用 XML,而记录集使用 COM。
- 记录集不能通过 HTTP 传输,而数据集可以。
(A) 详细解释连接池的基础知识。
首次打开连接时,会创建一个连接池,该连接池基于与创建连接对象时给定的连接字符串的精确匹配。连接池仅在连接字符串相同时才起作用。如果连接字符串不同,则将打开一个新连接,并且不会使用连接池。
让我尝试以图形方式解释这一点。在上面的图中,您可以看到有三个请求:Request1、Request2 和 Request3。Request1 和 Request3 具有相同的连接字符串,因此由于连接字符串相同,Request3 没有创建新的连接对象。它们共享相同的对象 ConObject1
。但是,由于连接字符串不同,为 Request2 创建了一个新对象 ConObject2
。
注意:连接字符串之间的区别在于一个连接字符串包含 "User id=sa",另一个包含 "User id=Testing"。
(A) ADO.NET 连接字符串中的最大连接池大小是多少?
最大连接池大小决定了可以池化的连接对象的最大数量。如果达到最大连接池大小并且没有可用的连接,则请求将排队,直到连接被释放回连接池。因此,在完成与 Connection 对象的工作后立即调用连接的 Close
或 Dispose
方法始终是一个好习惯。
(A) 如何启用和禁用连接池?
对于 .NET,它默认是启用的,但如果您想确保,请在连接字符串中设置 Pooling=true
。要禁用连接池,如果它是 ADO.NET 连接,请在连接字符串中设置 Pooling=false
。如果它是 OLEDB 连接对象,请在连接字符串中设置 OLE DB Services=-4
。
(I) ADO.NET 2.0 有哪些额外功能?
- 批量复制操作:从一个数据源到另一个数据源的批量复制是 ADO.NET 2.0 中新增的功能。ADO.NET 引入了批量复制类,它们提供了将数据从一个源传输到另一个源的最快方法。每个 ADO.NET 数据提供程序都有批量复制类。例如,在 SQL Server .NET 数据提供程序中,批量复制操作由
SqlBulkCopy
类处理,该类可以读取 DataSet、DataTable、DataReader 或 XML 对象。 - 数据分页:引入了一个新方法
ExecutePageReader
,它接受三个参数:CommandBehavior
、StartIndex
和PageSize
。因此,如果您只想获取 10-20 行,您可以简单地调用此方法,将起始索引设置为 10,页大小设置为 10。 - 批量更新:如果要更新大量数据,ADO.NET 2.0 提供了
UpdateBatchSize
属性,允许您设置批量更新的行数。这大大提高了性能,因为到服务器的往返次数被最小化了。 - Load 和 Save 方法:在 ADO.NET 的早期版本中,只有 DataSet 具有
Load
和Save
方法。Load
方法可以将 XML 等对象中的数据加载到 DataSet 对象中,Save
方法将数据保存到持久介质。现在 DataTable 也支持这两种方法。您还可以使用Load
方法将 DataReader 对象加载到 DataTable 中。 - 新的数据控件:在工具箱中,您可以看到三个新控件 -
DataGridView
、DataConnector
和DataNavigator
。 - DataReader 的新 Execute 方法:引入了一些新的 Execute 方法,包括
ExecutePageReader
、ExecuteResultSet
和ExecuteRow
。
如需进一步阅读,请观看以下面试准备视频和分步视频系列。