LINQ to SQL 中的批量 INSERT / UPDATE / DELETE






4.29/5 (15投票s)
本文讨论了使用 LINQ to SQL 进行涉及 INSERT / UPDATE 和 DELETE 的基于 SET 的操作。
引言
LINQ to SQL 是一个很棒的 ORM 工具。它为我们的面向数据的应用程序提供了便捷的数据访问。它也非常容易学习。在本文中,我们将讨论使用 LINQ to SQL 进行数据库操作的基于 SET 的操作。
背景
与许多其他 ORM 一样,它在数据插入、操作和删除方面并不是非常出色。虽然它允许所有这些操作,但就涉及大量数据操作的应用程序的性能而言,所有这些操作的效率都不高。当我们调用 DataContext
对象的 submitChanges()
方法时,这些操作会立即提交到数据库。对于涉及的每个记录,这些操作会作为单独的 INSERT
、UPDATE
或 DELETE
语句提交。当调用 submitChanges()
方法时,您可能会在 SQL Profiler 中注意到这些语句。
由于该系统本身不支持批量插入、操作或删除,因此我们需要自己提供此功能。
讨论
我们知道 LINQ to SQL 通过 DataContext
将存储过程作为一级公民支持。与实体一样,我们需要将存储过程的定义添加到我们的 DBML 文件中。此处提出的解决方案将使用存储过程。这不是一个通用的解决方案,但有助于对数据库实体执行批量操作。那些曾经在 .NET 中执行批量数据库操作的人可能已经使用过类似的、使用数据集的解决方案。这涉及到将 XML 发送到存储过程,并使用 OpenXML 来对我们的数据应用基于 SET 的操作。
为了展示解决方案,让我们在数据库中创建一个表。我正在使用 SQL Server 2005。我们正在创建一个名为 TBL_TEST_TEST 的表,该表有两个列(ID
和 Name
)。其中,ID
是一个标识列,它是表的主键。
CREATE TABLE [dbo].[TBL_TEST_TEST]
(
ID INT IDENTITY(1,1) PRIMARY KEY,
[NAME] [varchar](50)
)
我们创建一个名为 TestIQueryable.csproj 的 C# 控制台项目。
现在,我们将一个 LINQ to SQL 类项添加到我们的项目中,名为 Test.dbml。
将连接添加到 Server Explorer 中的数据库,然后将 TBL_TEST_TEST 拖到 Test.dbml 的 LINQ to SQL 设计器中。
现在让我们分别讨论每个操作。
批量插入
让我们开始向数据库插入批量数据。我们在数据库中创建一个存储过程,如下所示:
CREATE PROCEDURE [dbo].[spTEST_InsertXMLTEST_TEST](@UpdatedProdData nText)
AS
DECLARE @hDoc int
exec sp_xml_preparedocument @hDoc OUTPUT,@UpdatedProdData
INSERT INTO TBL_TEST_TEST(NAME)
SELECT XMLProdTable.NAME
FROM OPENXML(@hDoc, 'ArrayOfTBL_TEST_TEST/TBL_TEST_TEST', 2)
WITH (
ID Int,
NAME varchar(100)
) XMLProdTable
EXEC sp_xml_removedocument @hDoc
如前所述,我们将 XML 数据传递到 nText
参数的此存储过程中。我们使用 OpenXML 来获取数据并将其插入到我们的表中。
现在,我们打开 LINQ to SQL 设计器以将此存储过程添加到 Test.dbml。将存储过程从 Server Explorer 拖到设计器中用于存储过程的选项卡。将存储过程的名称更新为有意义的名称。我们将名称更新为 insertTestData
。
我们打开 Program.cs 并编写一些代码来生成数据。将以下代码添加到 Program
类的 Main
方法中:
using (TestDataContext db = new TestDataContext())
{
TBL_TEST_TEST[] testRecords = new TBL_TEST_TEST[50];
for (int count = 0; count < 50; count++)
{
TBL_TEST_TEST testRecord = new TBL_TEST_TEST();
testRecord.NAME = "Name : " + count;
testRecords[count] = testRecord;
}
StringBuilder sBuilder = new StringBuilder();
System.IO.StringWriter sWriter = new System.IO.StringWriter(sBuilder);
XmlSerializer serializer = new XmlSerializer(typeof(TBL_TEST_TEST[]));
serializer.Serialize(sWriter, testRecords);
db.insertTestData(sBuilder.ToString());
}
您可以看到,我们既没有使用 db.insertOnSubmit()
,也没有使用 submitChanges()
。但是,我们已经通过 LINQ to SQL 提供的 TBL_TEST_TEST
类型对象的数组生成了数据。在数组中生成数据后,我们使用 XMLSerializer
将其转换为 XML。我们直接使用 DataContext
对象将此 XML 传递给存储过程。
现在,我们终于成功地一次性向数据库插入了 50 行数据。
批量更新
您可能更感兴趣了解涉及 IQueryable
类型的操作。让我们在数据库中创建此存储过程:
CREATE PROCEDURE [dbo].[spTEST_UpdateXMLTEST_TEST](@UpdatedProdData nText)
AS
DECLARE @hDoc int
exec sp_xml_preparedocument @hDoc OUTPUT,@UpdatedProdData
UPDATE TBL_TEST_TEST
SET
TBL_TEST_TEST.NAME = XMLProdTable.NAME
FROM OPENXML(@hDoc, 'ArrayOfTBL_TEST_TEST/TBL_TEST_TEST', 2)
WITH (
ID Int,
NAME varchar(100)
) XMLProdTable
WHERE TBL_TEST_TEST.ID = XMLProdTable.ID
EXEC sp_xml_removedocument @hDoc
我们将此存储过程的定义添加到 Test.dbml:
您可以删除 Program.cs(Main
方法)中编写的代码。添加以下代码:
using (TestDataContext db = new TestDataContext())
{
var myPackages = from tbl in db.TBL_TEST_TESTs select tbl;
foreach (TBL_TEST_TEST t in myPackages)
{
t.NAME = t.NAME + " _Updated";
}
XmlSerializer serializer = new XmlSerializer(typeof(TBL_TEST_TEST[]));
StringBuilder sBuilder = new StringBuilder();
System.IO.StringWriter sWriter = new System.IO.StringWriter(sBuilder);
serializer.Serialize(sWriter, myPackages.ToArray<tbl_test_test>());
db.updateTestData(sBuilder.ToString());
}
在上面的代码中,我们使用 IQueryable
接口查询了数据库。获取数据后,我们使用 foreach
循环对其进行了更新。我们将其序列化为 XML 数据,并将其写入 StringBuilderObject sBuilder
。我们使用已添加的存储过程将此数据发送到数据库。这样,我们就实现了将批量数据发送到数据库进行更新。
批量删除
现在,最后,我们讨论批量删除。这几乎是相同的解决方案。区别仅仅在于,我们不是更新,而是删除数据。让我们尝试删除数据库中 ID 大于 25 的所有记录。
CREATE PROCEDURE [dbo].[spTEST_deleteTEST_TEST](@UpdatedProdData nText)
AS
DECLARE @hDoc int
exec sp_xml_preparedocument @hDoc OUTPUT, @UpdatedProdData
DELETE FROM TBL_TEST_TEST
WHERE ID IN
(
SELECT XMLProdTable.ID
FROM OPENXML(@hDoc, 'ArrayOfTBL_TEST_TEST/TBL_TEST_TEST', 2)
WITH (
ID Int,
NAME varchar(100)
) XMLProdTable
)
EXEC sp_xml_removedocument @hDoc
将此存储过程的定义添加到 Test.dbml 并将其重命名为 deleteTestData
。
与更新操作一样,将 Program.cs 的 Main
方法中的代码更新为如下所示:
using (TestDataContext db = new TestDataContext())
{
var myPackages = from tbl in db.TBL_TEST_TESTs
where tbl.ID > 25
select tbl;
XmlSerializer serializer = new XmlSerializer(typeof(TBL_TEST_TEST[]));
StringBuilder sBuilder = new StringBuilder();
System.IO.StringWriter sWriter = new System.IO.StringWriter(sBuilder);
serializer.Serialize(sWriter, myPackages.ToArray());
db.deleteTestData(sBuilder.ToString());
}
历史
- 文章发布日期:2010 年 1 月 20 日。