C# 检测复杂对象的更改
我有一个BO,其中包含一些依赖的BO(通过导航属性),它们表示数据库中的几个链接表。例如,个人主表和地址、教育表,通过个人地址、个人教育表1对多链接C# 检测复杂对象的更改,c#,.net,entity-framework,C#,.net,Entity Framework,我有一个BO,其中包含一些依赖的BO(通过导航属性),它们表示数据库中的几个链接表。例如,个人主表和地址、教育表,通过个人地址、个人教育表1对多链接 我们需要跟踪特定人员在人员、地址、教育表上发生的变化。这三个表中的任何更新都应将Person.LastRecordUpdate日期更新为当前日期。我认为跟踪Person表本身没有任何问题。但是,我们需要跟踪其他两个表(Address、Education)中的更改,这两个表具有AddressId、EducationId PKs和no PersonId
我们需要跟踪特定人员在人员、地址、教育表上发生的变化。这三个表中的任何更新都应将Person.LastRecordUpdate日期更新为当前日期。我认为跟踪Person表本身没有任何问题。但是,我们需要跟踪其他两个表(Address、Education)中的更改,这两个表具有AddressId、EducationId PKs和no PersonId(因为它们通过中间表与主表链接)。保存在地址中,教育发生在另一个dbcontext实体中,即保存人。如何解决此问题?我从包含
公共虚拟日期时间的模型库中派生所有业务对象?LastModified属性。它还实现了接口
public interface IHasLastModified
{
DateTime? LastModified { get; set; }
}
然后在myDbContext
中重写SaveChanges()
,以查找正在添加或修改的任何实现IHasLastModified
的内容,并设置修改后的时间戳
另一方面,EF在调试器中显示DbEntityValidationException
详细信息方面有些古怪。因此,在这段代码中,我也处理了这个问题
通过生成可在调试器中直接查看的errorList
异常,并记录详细信息。在我的代码中,logger
是一个NLog记录器。你可以
使用任何其他记录器,或移除该线路
public override int SaveChanges()
{
try
{
DateTime now = DateTime.UtcNow;
foreach (ObjectStateEntry entry in (this as IObjectContextAdapter).ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
{
//logger.Info("Setting LastModified on " + entry.Entity.GetType().FullName);
if (!entry.IsRelationship)
{
IHasLastModified lastModified = entry.Entity as IHasLastModified;
if (lastModified != null)
lastModified.LastModified = now;
}
}
return base.SaveChanges();
}
catch (DbEntityValidationException valEx)
{
List<string> errorList = new List<string>();
foreach (var error in valEx.EntityValidationErrors)
{
foreach (var entry in error.ValidationErrors)
{
errorList.Add(entry.PropertyName + ": " + entry.ErrorMessage);
}
logger.Error(string.Join(";", errorList));
}
throw;
}
}
public override int SaveChanges()
{
尝试
{
DateTime now=DateTime.UtcNow;
foreach(中的ObjectStateEntry条目(作为IOObjectContextAdapter)。ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
{
//logger.Info(“在“+entry.Entity.GetType().FullName”上设置LastModified);
如果(!entry.IsRelationship)
{
IHasLastModified lastModified=条目。实体为IHasLastModified;
如果(lastModified!=null)
lastModified.lastModified=现在;
}
}
返回base.SaveChanges();
}
捕获(DbEntityValidationException valEx)
{
List errorList=新列表();
foreach(valEx.EntityValidationErrors中的var错误)
{
foreach(var条目出错。ValidationErrors)
{
errorList.Add(entry.PropertyName+:“+entry.ErrorMessage);
}
logger.Error(string.Join(“;”,errorList));
}
投掷;
}
}
保存在地址中,教育发生在另一个dbcontext实体中,即保存人
跨多个DbContext实例合并更改是非常非常棘手的。EF并不是为所有场景提供完全支持
我强烈建议避免这种情况。传递DbContext的单个实例,而不是尝试合并来自两个DbContext映像的更改
如果您确实想尝试和管理在两个上下文实例中发生的更改,请查看。注意结论意见
到目前为止,EF不支持完全对象图合并,并将其留给您自己管理
你为什么要用摇摆台来做一对多的桌子?你的意思是多对多关系(许多用户可以拥有相同的教育或地址)?我通常会覆盖SaveChanges
,但使用LastModified
的界面是一个很好的主意。我将在我的下一个项目中实施它!Eric,您的解决方案在这种情况下有何帮助:假设我有以下数据库内容:Person.LastRecordUpdate;我在地址表中还有一个地址记录,它通过Person_地址表与Person表链接(正确,多对多)。我修改了地址记录中的邮政编码,那么我应该如何跟踪它,以便能够自动更新Person.LastRecordUpdate值?@TakhirMamirov:保存的每个实体都会自动应用时间戳。将我的LastModified
更改为您的LastRecordUpdate
。不管是父母还是孩子,让我把任务复杂化。MemberInfo表与person 1对1链接。有一个字段MemberInfo.LastModified。还有那两个卫星表-教育,地址,和人联系。问题:在DB中修改教育或地址实体时,需要MemberInfo.LastModified更新。请共享哪些类应继承该BaseModel,哪些不应继承,以及哪些类应具有LastModified属性。注:并非所有BO都需要该属性。只有MemberInfo。简单。。。每个需要自动设置时间戳的对象都继承自ModelBase。