将尚未分配的 ID 分配给新实体

Posted

技术标签:

【中文标题】将尚未分配的 ID 分配给新实体【英文标题】:Assign a yet unassigned ID to a new entity 【发布时间】:2015-07-23 16:09:18 【问题描述】:

我们正在尝试建立一个卷影复制系统来审核我们项目数据库中的一些表。对于任何更改(添加、更新、删除),该记录的副本都会保存到它的影子表中(我们使用术语版本)。

如果我们有一个名为 Profiles 的表,其中包含 (int)ProfileId、(varchar(50))Name、(date)UpdateDate 等列...我们将有另一个名为 ProfilesVersion 的表,其中包含 (int)ProfileVersionId、(int )ProfileId, (varchar(50))Name, (date)UpdateDate 等...

我正在制作系统以制作副本。过去,我使用数据库中的触发器来捕获插入、更新、删除。但现在我们正在尝试使用 Entity Framework 和 Linq 来实现。

我可以覆盖 DbContext 上的 SaveChanges,并在 Version 表中获取第二个副本。但是,在第一个表中填充的键 Id 不会最终出现在 Version 表中。

使用 Entity Framework,您可以对数据库进行两次插入,将来自一个实体的数据应用到第二个实体。例如:

var res = new Resource
    SomeValue = someParameter
;
_db.Resource.Add(res);

var newProfile = new Profile
    ProfileValue = anotherParameter, 
    ForeignResourceId = res.ResourceId // ResourceId is autogenerated
;

_db.Profile.Add(newProfile);
_db.SaveChanges();

var forResourceId = newProfile.ForeignResourceId; 

由于 Profile.ForeignResourceId 和 Resource.ResourceId 在模型中映射,newProfile 对象具有数据库在 SaveChanges() 之后分配的 ForeignResourceId。不知何故,实体框架知道一旦从数据库生成 res.ResourceId 就将其放入 ForeignResourceId。

我的代码将值从一个实体动态复制到版本表中并没有这样做。它只是将数据从第一个实体复制到版本实体的新记录中,但没有设置关系以使用外键填充键字段。

public int SaveChanges(Guid userId)

    // ... some other code

    // entityEntry is DbEntityEntry, the entity with changes we want to replicate

    // Create audit entity.
    DbSet set = this.Set(auditTypeInfo.AuditEntityType);
    IAuditEntity auditEntity = set.Create() as IAuditEntity;
    set.Add(auditEntity);

    // Copy the properties.
    DbEntityEntry auditEntityEntry = this.Entry(auditEntity);
    foreach (string propertyName in auditTypeInfo.AuditProperties)
    
        // This copies just the raw value, if any
        auditEntityEntry.Property(propertyName).CurrentValue = entityEntry.Property(propertyName).CurrentValue; 
    

    // ... 

    return base.SaveChanges();

因此,按照我们的示例,如果我们添加一个 Profile 记录,它会得到它的 ProfileId,但 ProfileVersion 记录不会。

如何在上面的代码中让实体框架在我们复制到的“审计”中设置该值?

【问题讨论】:

如果Resource 有一个自动生成的键值,上面的代码也不起作用:当你将它分配给ForeignResourceId 时,res.ResourceId 将为零。审计实体应具有引用源实体的导航属性,而不是原始 FK 属性。 我认为因为模型中映射的关系是它起作用的原因。但是,我相信您所说的导航属性是正确的。如何动态设置? 我认为只有当你的类有基类时你才能这样做。审计实体可以具有基本类型的导航属性。 【参考方案1】:

如果我正确理解了你的情况,那么:

这将与您的实体的属性有关。如果你的实体有属性(我想,它是你实体的键)有DatabaseGeneratedOption.Identity(分配在OnModelCreating),在sql级别转换为IDENTITY (1,1),你无能为力,因为所有这些正在数据库中处理,而不是 ORM 级别。

在这种情况下你可以做什么,使用IDENTITY_INSERT,这将允许你分配 Id,但这意味着你还必须手动生成 Id。

简而言之 - 摆脱自动身份生成。

【讨论】:

澄清了我在寻找什么。

以上是关于将尚未分配的 ID 分配给新实体的主要内容,如果未能解决你的问题,请参考以下文章

将性别变量分配给新列

如何分配尚未分配的最低编号

IDEA:“将语句分配给新的局部变量”?

分配给新变量后如何测试道具

如何以最有效的方式将运动员的名字分配给新列“名字”? [复制]

javascript 将JS Object的数据分配给新的JS Object