c# - SET IDENTITY_INSERT [表] ON 不起作用

标签 c# sql-server entity-framework

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

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

SET IDENTITY_INSERT [CRMTItem] ON;

但是,当我从 C# 插入 Id 为 1 的项目时,Id 仍在从 850 左右递增。

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

这是我的插入代码,如您所见,我在插入之前确保 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");

但是还是不行。

根据我发现的另一个问题,我接下来尝试了这个:

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();

现在我收到一个错误

Explicit value must be specified for identity column in table 'CRMTItem' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.

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

最佳答案

当您从数据库生成模型时, Entity Framework 将使用 StoreGeneeratedPattern.Identity 将所有标识列映射到模型属性。就您而言,据我了解,此类属性是 crmtItem.Id 。当您插入 crmItem 时 - Entity Framework 将忽略您为标识属性设置的值(如果您设置了任何值),因为它知道该值是由数据库提供的,因此它知道是否尝试在插入语句 - 数据库将返回错误。

Entity Framework 不了解IDENTITY_INSERT,因此它将始终根据目标模型属性的StoreGeneratePattern元数据进行操作。如果它是 IdentityCompulated - 无论您做什么,它都不会在插入时为其提供值。如果它设置为None - 那么它将提供一个值(无论如何)。

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

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

当你这样做时:

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

这仍然在单独的 session 中执行,而不是在 SaveChanges 将执行的同一个 session 中执行。因此,要在同一个 session 中执行 IDENTITY_INSERTSaveChanges - 您需要将它们包装在事务中,正如您已经弄清楚的那样。

关于c# - SET IDENTITY_INSERT [表] ON 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49123642/

相关文章:

c# - 如何使用 EF 迁移将 int ID 列更改为 Guid?

c# - Entity Framework 6 Code First 查找表未填充

mysql - 更新分区/组中最新记录中的列

sql - 在使用 View 的查询中使用WITH NOLOCK 表提示 - 它是否在 View 内传播?

entity-framework - 无法创建类型为 'System.Object'的常量值。在这种情况下,仅支持基本类型('such as Int32, String, and Guid')。

c# - 如何在 EF 4.1 RC 中的 DbContext 级别关闭更改跟踪?

c# - 如何轻松地从一个解决方案中迁移所有项目

sql - 间隙和岛屿 : Splitting Islands Based On External Table

entity-framework - 在 Entity Framework 6 中的一个事务中删除多行时重复查询

c# - 多态关联和拆分表