如何检查 DbContext 是否正在跟踪具有相同键值 {'id'} 的实体?

Lie*_*ero 1 c# change-tracking entity-framework-core .net-5

我认为这个问题是不言自明的:

如何检查具有相同键值 {'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
   }
})
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 6

您要求的功能存在(例如,作为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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

唯一的问题是使用标记为“内部基础设施”一部分的代码,因此您会收到一些警告。只需忽略或抑制它们即可。上述代码适用于 EF Core 3.x 和 EF Core 5.x ,并且如果将来的 EF Core 版本中发生某些更改,可以/应该进行调整。如果你问我,与其浪费时间创建代码分析器来显示此类警告,不如公开像这样缺少的有用功能。无论如何,事情就是这样,我们应该利用他们给我们的东西。