我们正在尝试设置卷影副本系统,以审核项目数据库中的某些表。对于任何更改(添加,更新,删除),该记录的副本将保存到其影子表中(我们使用的是术语版本)。
如果我们有一个名为Profiles的表,其中包含列(int)ProfileId,(varchar(50))Name,(date)UpdateDate等...我们将有另一个名为ProfilesVersion的表,其中包含列(int)ProfileVersionId,(int )ProfileId,(varchar(50))名称,(日期)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。
我将代码从一个实体动态复制到Version表中的代码不会这样做。它只是将第一个实体的数据复制到Version实体的新记录中,但是没有设置关系以使用外键填充关键字段。
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记录没有。
在上面的代码中,如何让实体框架在我们要复制的'auditentity'中设置该值?
答案 0 :(得分:0)
如果我理解你的情况,那么:
这将与您的实体的属性有关。如果你的实体有属性(我想,它是你实体的关键)有DatabaseGeneratedOption.Identity
(在OnModelCreating
分配),在sql级别转换为IDENTITY (1,1)
,你什么都没有do,因为所有这些都是在数据库处理,而不是ORM级别。
在这种情况下您可以做什么,使用IDENTITY_INSERT
,这将允许您分配ID,但是,这意味着您还必须手动生成ID。
简而言之 - 摆脱自动身份生成。