Linq To Sql 和 identity_insert

5

我正在尝试在一个主键为Identity字段的表上进行记录插入。

我尝试调用
mycontext.ExecuteCommand("SET identity_insert myTable ON")
但这没有起到任何作用。

当我提交更改时,我会收到一个错误,说IDENTITY_INSERTOFF

在提交更改之前,我如何从C#代码中将其打开?

编辑

我已经读到了这是因为ExecuteCommand的代码在不同的会话中执行。

编辑2

是否有任何方法可以在我的C#代码中执行一些DDL来删除Identity规范,然后进行插入,最后再打开Identity规范?


1
为什么你想要打开identity insert,这是一件非常危险的事情(它不仅影响你的进程),除非数据库处于维护模式或者你确定(这意味着没有其他用户有权限这样做),否则不应该对生产数据进行操作。在你执行任务的同时,没有其他用户能够向表中输入数据。 - HLGEM
2
这不是生产数据库。我正在将数据迁移到开发数据库。 - Ronnie Overby
6个回答

19

另一个选项是将所有的Linq2Sql调用都包裹在TransactionScope()中。这样应该可以强制它们在同一连接中运行。

using System.Transactions; // Be sure to add a reference to System.Transactions.dll to your project.

       // ... in a method somewhere ...
       using (System.Transaction.TransactionScope trans = new TransactionScope())
       {
          using(YourDataContext context = new YourDataContext())
          {
             context.ExecuteCommand("SET IDENTITY_INSERT MyTable ON");

             context.ExecuteCommand("yourInsertCommand");

             context.ExecuteCommand("SET IDENTITY_INSERT MyTable OFF");
          }
          trans.Complete();
       }
       // ...

虽然,如果你试图做这样的事情:

context.ExecuteCommand("SET IDENTITY_INSERT MyTable ON");
context.MyTable.InsertOnSubmit(myTableObject)
context.SubmitChanges()
context.ExecuteCommand("SET IDENTITY_INSERT MyTable OFF");

你可能会遇到其他问题,特别是如果标识列设置了IsDbGenerated属性为true。Linq2Sql生成的SQL命令将不知道包括标识列和值。


这就是该死的解决方案!所以它是可能的! - Roel

4
你需要在一个单独的T-SQL代码块中完成所有步骤——如果你想打开它,然后执行你的LINQ-to-SQL查询,然后再关闭它,这将非常困难,甚至是不可能的:(唯一真正的解决方案是将整个SQL打包成一个SQL语句并执行它:
SET IDENTITY_INSERT MyTable ON

(do your update here)

SET IDENTITY_INSERT MyTable OFF

并使用.ExecuteContext()将其作为单个代码块执行

Marc

PS:对于您的EDIT#2:不幸的是,没有(简单的)方法可以从列中删除标识,并重新启用它。基本上,您必须创建一个没有IDENTITY的新列,将值复制过去,删除IDENTITY列,然后在完成时反向执行相同的操作 - 抱歉!:-(

PS#2:这真的引发了一个问题:到底需要进行“identity insert”?定期从应用程序中进行吗?当然-您可能偶尔会遇到这种需求,但我总是会在SQL Mgmt Studio中单独执行此操作-肯定不是在我的应用程序中.....(只是好奇您的用例/动机是什么)。


@PS#2看看这个:http://stackoverflow.com/questions/1368494/transfer-transform-data-from-sql-server-2008-db-to-another我本来想着直接开始编码,但最后可能会学习SSIS。有什么建议吗? - Ronnie Overby
1
我从未说过这是常规的。我正在传输/转换数据,但我对SSIS一窍不通。 - Ronnie Overby
好的,既然这样,为什么不直接使用SQL呢?是的 - Linq很好用 - 但如果只是一次性的操作 - 直接使用普通的SQL语句就可以避免所有问题和限制了 :-) - marc_s
要么在您的应用程序中使用直接SQL,要么选择SSIS - 这确实是SSIS存在的全部原因 - 从一个源提取-转换-加载数据到另一个源 :-) - marc_s

3

在执行命令之前手动打开连接应该就足够了。这样可以使命令在同一会话中运行:

context.Connection.Open();
context.ExecuteCommand("SET IDENTITY_INSERT MyTable ON");
// make changes
// ...
context.SubmitChanges();

我知道建议避免使用 +1 和"谢谢",但是我实在忍不住了。我卡在这个问题上几个小时了。我正在使用Context和Linq to SQL,并提交更改,但总是提示IDENTITY_INSERT关闭。我只需要打开连接就好了。谢谢! - Paul

0

我曾遇到过同样的错误信息,解决方法是更改表中主键的属性。

MyTable.MyId int IDENTITY(1,1) NOT NULL

dbml 中的属性设置 MyId

  • 自动生成值: True;
  • 自动同步: OnInsert;
  • 主键: True;
  • 服务器数据类型: int NOT NULL IDENTITY;
  • 类型: int;

1
这些是默认设置...你实际上改了什么? - AlbatrossCafe

0

每次添加新记录时,只需简单地使用自定义ID重新生成身份密钥,例如:

reseed identity key

    using (var desDb = new DesDbContext())
    {
        // del-table-all --------------------------------------------------------
        desDb.Database.ExecuteSqlCommand("DELETE FROM [Products]");

        foreach (var desItem in desList) //desList is List of Product
        {
            // reseed identity key
            desDb.Database.ExecuteSqlCommand("DBCC CHECKIDENT('Products', RESEED," 
                + (desItem.ProductID - 1) + ");");

            // and record
            desDb.Products.Add(desItem);                        

            // save-db                    
            desDb.SaveChanges();

        }
    }

0
我所做的是类似于这样的事情(使用Nbuilder来创建实体)。我通常创建所有行,除了标识插入行;这一步在最后完成。这只是测试数据的创建,因此不需要事务。
using (var entitiesEfContext = new ContextABC())
{

    var platforms = Builder<Platform>
                                .CreateListOfSize(4)
                                .TheFirst(1)
                                .With(x => x.Description = "Desc1")
                                .With(x => x.IsDeleted = false)
                                .TheNext(1)
                                .With(x => x.Description = "Desc2")
                                .With(x => x.IsDeleted = false)
                                .TheNext(1)
                                .With(x => x.Description = "Desc3")
                                .With(x => x.IsDeleted = false)
                                .TheNext(1)
                                .With(x => x.Description = "Desc4")
                                .With(x => x.IsDeleted = false)
                                .Build();
                foreach (var platform in platforms)
                {
                    entitiesEfContext.Platform.AddObject(platform);
                }
                entitiesEfContext.SaveChanges();

              // the identity insert row (o as id in my case)

               entitiesEfContext.ExecuteStoreCommand("SET IDENTITY_INSERT Platform ON; INSERT INTO [Platform](Platformid,[Description],[IsDeleted],[Created],[Updated]) VALUES (0,'Desc0' ,0 ,getutcdate(),getutcdate());SET IDENTITY_INSERT Platform Off");


              }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接