我想在指定 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
元数据进行操作。如果它是 Identity
或 Compulated
- 无论您做什么,它都不会在插入时为其提供值。如果它设置为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_INSERT
和 SaveChanges
- 您需要将它们包装在事务中,正如您已经弄清楚的那样。
关于c# - SET IDENTITY_INSERT [表] ON 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49123642/