如何检查 DbContext 是否正在跟踪具有相同键值 {'id'} 的实体?
How to check whether an entity with the same key value for {'id'} is being tracked by DbContext?
我认为这个问题是不言自明的:
如何检查是否正在跟踪与 {'id'} 具有相同键值的实体?
例如:
var blog = anotherDbContext.Blogs.Include(b => b.Posts).Find(...);
dbContext.ChangeTracker.AttachGraph(blog, node => {
if (node.Entry.State == EntityState.Detached) {
//how do I check, whether there is already an entity with the same key as node.Entity
node.Entry.State = EntityState.Unchanged; //this might throw InvalidOperationException
}
})
上下文中的每个 table 都是一个 DbSet<TEntity>
。这有一个 属性 Local
。这是所有可用的实体,已加载。您可以在不生成对真实服务器的调用的情况下搜索实体。
var objFromLocalLinqQuery = dbContext.Blogs.Local.Find(...);
然后你可以通过调用
获得EntityEntry<>
var entity = context.Entry(objFromLocalLinqQuery);
var state = entity.Entry.State;
您要求的功能存在(例如,作为 Find
方法的一部分),但不幸的是没有公开(由于某些未知原因,他们认为它对他们没有用,让只是在它发生时抛出异常)。
但由于 EF Core 代码是开源的,因此不难提取使用与 Find
内部实现类似方法的自定义扩展方法(您可以搜索 Local
属性 的 DbSet
,但很难用非通用代码获取它,效率低下并且必须处理未知键 属性 名称和类型 - 全部已经由内部代码处理)。方法如下:
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Microsoft.EntityFrameworkCore
{
public static class ChangeTrackerExtensions
{
public static object FindTracked(this DbContext context, object entity)
{
var entityType = context.Model.FindRuntimeEntityType(entity.GetType());
var key = entityType.FindPrimaryKey();
var keyProperties = key.Properties;
var keyValues = new object[keyProperties.Count];
for (int i = 0; i < keyValues.Length; i++)
keyValues[i] = keyProperties[i].GetGetter().GetClrValue(entity);
var stateManager = context.GetService<IStateManager>();
return stateManager.TryGetEntry(key, keyValues)?.Entity;
}
}
}
唯一的问题是使用标记为“内部基础结构”一部分的代码,因此您会收到一些警告。只需忽略或抑制它们即可。以上代码在 EF Core 3.x 和 EF Core 5.x,如果某些未来的 EF Core 版本发生了变化,could/should 将被调整。如果你问我,与其浪费时间创建代码分析器来显示此类警告,他们会最好像这样把缺失的和有用的功能暴露出来。反正就是这样,我们应该用他们给我们的东西。
我认为这个问题是不言自明的:
如何检查是否正在跟踪与 {'id'} 具有相同键值的实体?
例如:
var blog = anotherDbContext.Blogs.Include(b => b.Posts).Find(...);
dbContext.ChangeTracker.AttachGraph(blog, node => {
if (node.Entry.State == EntityState.Detached) {
//how do I check, whether there is already an entity with the same key as node.Entity
node.Entry.State = EntityState.Unchanged; //this might throw InvalidOperationException
}
})
上下文中的每个 table 都是一个 DbSet<TEntity>
。这有一个 属性 Local
。这是所有可用的实体,已加载。您可以在不生成对真实服务器的调用的情况下搜索实体。
var objFromLocalLinqQuery = dbContext.Blogs.Local.Find(...);
然后你可以通过调用
获得EntityEntry<>
var entity = context.Entry(objFromLocalLinqQuery);
var state = entity.Entry.State;
您要求的功能存在(例如,作为 Find
方法的一部分),但不幸的是没有公开(由于某些未知原因,他们认为它对他们没有用,让只是在它发生时抛出异常)。
但由于 EF Core 代码是开源的,因此不难提取使用与 Find
内部实现类似方法的自定义扩展方法(您可以搜索 Local
属性 的 DbSet
,但很难用非通用代码获取它,效率低下并且必须处理未知键 属性 名称和类型 - 全部已经由内部代码处理)。方法如下:
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Microsoft.EntityFrameworkCore
{
public static class ChangeTrackerExtensions
{
public static object FindTracked(this DbContext context, object entity)
{
var entityType = context.Model.FindRuntimeEntityType(entity.GetType());
var key = entityType.FindPrimaryKey();
var keyProperties = key.Properties;
var keyValues = new object[keyProperties.Count];
for (int i = 0; i < keyValues.Length; i++)
keyValues[i] = keyProperties[i].GetGetter().GetClrValue(entity);
var stateManager = context.GetService<IStateManager>();
return stateManager.TryGetEntry(key, keyValues)?.Entity;
}
}
}
唯一的问题是使用标记为“内部基础结构”一部分的代码,因此您会收到一些警告。只需忽略或抑制它们即可。以上代码在 EF Core 3.x 和 EF Core 5.x,如果某些未来的 EF Core 版本发生了变化,could/should 将被调整。如果你问我,与其浪费时间创建代码分析器来显示此类警告,他们会最好像这样把缺失的和有用的功能暴露出来。反正就是这样,我们应该用他们给我们的东西。