翼度科技»论坛 编程开发 .net 查看内容

EFCore如何更改跟踪状态

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
这里简单介绍下几种修改实体或者导航的跟踪状态。
1. 直接修改实体

对已在DbContext中跟踪的实体,直接操作,如给字段赋值、给导航属性赋值或者添加删除等
对未在DbContext中跟踪的实体,调用DbContext的Add、Update、Remove等方法,对已跟踪的实体也有效
需要注意所有添加的实体都需要调用DbContext.Add方法
2. 利用IStateManager.ChangingState(InternalEntityEntry,EntityState)

这个很简单,关键的是如何获得InternalEntityEntry,方法是调用IStateManager.TryGetEntry方法返回获得,该方法多个重载,主要都是传实体或者主键。
  1. Type type = ....// 实体类型
  2. DbContext ctx=...
  3. var entityType = ctx.Model.FindEntityType(type);
  4. var key = entityType.FindPrimaryKey();
  5. var internalEntityEntry = ((IDbContextDependencies)ctx).StateManager.TryGetEntry(key,主键值);
  6. ((IDbContextDependencies)ctx).StateManager.ChangingState(internalEntityEntry,EntityState.Modified);
复制代码
传主键同样可以获得隐式定义的ISkipNavigation的InternalEntityEntry,请看5中示例。
3. 利用集合导航属性的INavigationBase.GetCollectionAccessor()

INavigationBase.GetCollectionAccessor()返回IClrCollectionAccessor类型,使用它的Add和Remove方法操作集合,但是这里只针对已经在DbContext跟踪的才有效果,否则请参考5中的做法。
4. 利用IStateManager.InternalEntityEntryNotifier.NavigationCollectionChanged

对于已经跟踪的实体或导航,还可以NavigationCollectionChanged方法更改添加或者删除,主要是针对集合导航属性。
  1. Object entity=...//实体对象,假设它有个集合导航属性:Data
  2. var navigationEntry = ctx.Entry(entity).Navigation("Data");
  3. var obj = entity.Data.First();//假设不为空
  4. //将集合导航属性Data中obj修改成添加状态(EntityState.Added)
  5. ((IDbContextDependencies)ctx).StateManager.InternalEntityEntryNotifier.NavigationCollectionChanged(ctx.Entry(entity).GetInfrastructure(), navigationEntry.Metadata, new[] { obj }, Array.Empty<object>());
  6. //将集合导航属性Data中obj修改成删除状态(EntityState.Deleted)
  7. ((IDbContextDependencies)ctx).StateManager.InternalEntityEntryNotifier.NavigationCollectionChanged(ctx.Entry(entity).GetInfrastructure(), navigationEntry.Metadata, Array.Empty<object>(), new[] { obj });
复制代码
5. ISkipNavigation的状态修改

在第4点中,对于ISkipNavigation,无法修改导航的状态为EntityState.Unchanged,那么这里可以这么做。
  1. if (navigationEntry.Metadata is ISkipNavigation skipNavigation)
  2. {
  3.     var targetEntry = ((IDbContextDependencies)ctx).StateManager.GetOrCreateEntry(obj, navigationEntry.Metadata.TargetEntityType);
  4.     var key = skipNavigation.JoinEntityType.FindPrimaryKey();
  5.     var a = ctx.Entry(entity).GetInfrastructure()[skipNavigation.ForeignKey.PrincipalKey.Properties[0]];
  6.     var b = targetEntry[skipNavigation.Inverse.ForeignKey.PrincipalKey.Properties[0]];
  7.     var joinEntry = ((IDbContextDependencies)ctx).StateManager.TryGetEntry(key, new[] { a, b });
  8.     joinEntry.SetEntityState(EntityState.Unchanged);//也可以用IStateManager.ChangingState
  9. }
复制代码
如果ISkipNavigation还是未跟踪的,那么上面的代码joinEntry获得的是null,可以在上面代码之前加这两行就可以了。
  1. ((IDbContextDependencies)ctx).StateManager.CompleteAttachGraph()
  2. ((IDbContextDependencies)ctx).StateManager.InternalEntityEntryNotifier.NavigationCollectionChanged(ctx.Entry(entity).GetInfrastructure(), navigationEntry.Metadata, new[] { obj }, Array.Empty<object>());
复制代码
来源:https://www.cnblogs.com/pains/p/18558548
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具