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

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.29/5 (15投票s)

2010 年 1 月 21 日

CPOL

4分钟阅读

viewsIcon

191777

downloadIcon

1970

本文讨论了使用 LINQ to SQL 进行涉及 INSERT / UPDATE 和 DELETE 的基于 SET 的操作。

引言

LINQ to SQL 是一个很棒的 ORM 工具。它为我们的面向数据的应用程序提供了便捷的数据访问。它也非常容易学习。在本文中,我们将讨论使用 LINQ to SQL 进行数据库操作的基于 SET 的操作。

背景

与许多其他 ORM 一样,它在数据插入、操作和删除方面并不是非常出色。虽然它允许所有这些操作,但就涉及大量数据操作的应用程序的性能而言,所有这些操作的效率都不高。当我们调用 DataContext 对象的 submitChanges() 方法时,这些操作会立即提交到数据库。对于涉及的每个记录,这些操作会作为单独的 INSERTUPDATEDELETE 语句提交。当调用 submitChanges() 方法时,您可能会在 SQL Profiler 中注意到这些语句。

由于该系统本身不支持批量插入、操作或删除,因此我们需要自己提供此功能。

讨论

我们知道 LINQ to SQL 通过 DataContext 将存储过程作为一级公民支持。与实体一样,我们需要将存储过程的定义添加到我们的 DBML 文件中。此处提出的解决方案将使用存储过程。这不是一个通用的解决方案,但有助于对数据库实体执行批量操作。那些曾经在 .NET 中执行批量数据库操作的人可能已经使用过类似的、使用数据集的解决方案。这涉及到将 XML 发送到存储过程,并使用 OpenXML 来对我们的数据应用基于 SET 的操作。

为了展示解决方案,让我们在数据库中创建一个表。我正在使用 SQL Server 2005。我们正在创建一个名为 TBL_TEST_TEST 的表,该表有两个列(IDName)。其中,ID 是一个标识列,它是表的主键。

CREATE TABLE [dbo].[TBL_TEST_TEST]
(
    ID INT IDENTITY(1,1) PRIMARY KEY,
    [NAME] [varchar](50) 
)

我们创建一个名为 TestIQueryable.csproj 的 C# 控制台项目。

Create_Project.JPG

现在,我们将一个 LINQ to SQL 类项添加到我们的项目中,名为 Test.dbml

AddDbml.JPG

将连接添加到 Server Explorer 中的数据库,然后将 TBL_TEST_TEST 拖到 Test.dbml 的 LINQ to SQL 设计器中。

DragEntity.JPG

现在让我们分别讨论每个操作。

批量插入

让我们开始向数据库插入批量数据。我们在数据库中创建一个存储过程,如下所示:

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

InsertProcedureDBML.JPG

我们打开 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.csMain 方法)中编写的代码。添加以下代码:

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.csMain 方法中的代码更新为如下所示:

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 日。
© . All rights reserved.