SET IDENTITY_INSERT [table] ON无效

问题描述 投票:1回答:1

我想在我指定Id的位置插入一些记录,以便在我希望保持现有关系完整性的地方迁移数据。

为此,我直接在桌面上的SSMS中运行此命令:

SET IDENTITY_INSERT [CRMTItem] ON;

然而,当我从C#插入Id为1的项目时,Id仍然从850左右开始递增。

我从EDMX中删除了实体并再次从DB更新,但结果相同。

这是我的插入代码,你可以看到我在插入之前确保Id确实是1,但这只是被忽略了..

var crmtItem = new CRMTItem();

crmtItem.Id = adv.PrimaryId;
crmtItem.ProjectTitle = adv.ProjectTitle;
crmtItem.CreatedByUser = (adv.CreatedBy == null) ? (Guid?)null : new Guid(adv.CreatedBy);
crmtItem.Opportunity = (adv.Opportunity == null) ? (Guid?)null : new Guid(adv.Opportunity);
crmtItem.BidNoBid = adv.Bnb;
crmtItem.SPUrl = adv.SPUrl;
crmtItem.BnbId = (adv.BnbId == null) ? (Guid?)null : new Guid(adv.BnbId);
crmtItem.Stage = adv.ProjectStage;
crmtItem.Confidential = adv.Confidential;
crmtItem.OpportunityStatus = adv.OpportunityStatus;
crmtItem.OpportunityNumber = adv.OpportunityNumber;
crmtItem.CRMTNumber = adv.CrmtNumber;
crmtItem.ProjectNumber = adv.ProjectNumber;
crmtItem.Sector = adv.Sector;
crmtItem.Service = adv.Service;
crmtItem.CreatedDate = adv.CreatedDate;
crmtItem.Archive = adv.Archive;
crmtItem.ProjectManager = adv.ProjectManager;
crmtItem.WorkTeam = adv.WorkTeam;
crmtItem.Custodian = adv.Custodian;

db.CRMTItems.Add(crmtItem);

if (adv.PrimaryId == 1 || adv.PrimaryId == 2 || adv.PrimaryId == 3)
{
    await db.SaveChangesAsync();
}

我也尝试在插入项目之前添加此行

db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[CRMTItem] ON");

但它仍然无效。

基于我发现的另一个SO问题,我接下来尝试了这个:

db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[CRMTItem] ON");
db.CRMTItems.Add(crmtItem);

if (adv.PrimaryId == 1)
{
    await db.SaveChangesAsync();
}
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[CRMTItem] OFF");
transaction.Commit();

现在我收到了一个错误

当IDENTITY_INSERT设置为ON或复制用户插入NOT FOR REPLICATION标识列时,必须为表'CRMTItem'中的标识列指定显式值。

我错过了什么吗?为什么控制我自己的数据必须如此困难?如果我无法实现这一点,我将被迫在我的表中创建一个临时列只是为了存储原始(CDS)表中的id,这绝对是荒谬的,毕竟它是我的数据,为什么我不能选择列的值!?!?!

c# sql-server entity-framework
1个回答
1
投票

从数据库生成模型时 - Entity Framework将使用StoreGeneratedPattern.Identity将所有标识列映射到模型属性。在你的情况下,据我所知,这样的财产是crmtItem.Id。当你插入crmItem时 - 实体框架会忽略你为身份属性设置的值(如果你设置了任何),因为它知道这个值是由数据库提供的,所以它知道它是否试图在insert语句中提供这样的值 - 数据库将返回一个错误。

实体框架不了解IDENTITY_INSERT,因此它将始终根据目标模型属性的StoreGeneratedPattern元数据进行操作。如果它是IdentityComputed - 无论你做什么,它都不会为插入物提供价值。如果它被设置为None - 那么它将提供一个值(无论如何)。

因此,对于您的情况,您需要在EDMX设计器中将此属性设置为None以获取目标属性(CRMTItem.Id)。当然,在这之后 - 你必须在插入时始终提供这个值。

问题的另一部分,IDENTITY_INSERT没有得到尊重,你已经解决但仍然值得一些解释。此设置是会话范围的,因此当您在SSMS中执行它然后尝试从您的应用程序插入时 - 它没有任何效果:SSMS和您的应用程序在不同的会话中。

当你这样做时:

db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[CRMTItem] ON");

这仍然在单独的会话中执行,而不是在你的SaveChanges将执行。所以要在同一个会话中执行IDENTITY_INSERTSaveChanges - 你需要将它们包装在事务中,正如你已经想到的那样。

© www.soinside.com 2019 - 2024. All rights reserved.