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

C# 如何检查DbContext是否正在跟踪{'id'}具有相同键值的实体?,c#,entity-framework-core,.net-5,change-tracking,C#,Entity Framework Core,.net 5,Change Tracking,我认为这个问题不言自明: 如何检查是否正在跟踪{'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, wheth

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

如何检查是否正在跟踪{'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
   }
})

上下文中的每个表都是一个DbSet。这有一个很好的地方特色。以下是加载的所有实体都可用。您可以搜索实体,而无需生成对实际服务器的调用

var objFromLocalLinqQuery = dbContext.Blogs.Local.Find(...);
然后您可以通过调用获取EntityEntry

var entity = context.Entry(objFromLocalLinqQuery);
var state = entity.Entry.State;

上下文中的每个表都是一个DbSet。这有一个很好的地方特色。以下是加载的所有实体都可用。您可以搜索实体,而无需生成对实际服务器的调用

var objFromLocalLinqQuery = dbContext.Blogs.Local.Find(...);
然后您可以通过调用获取EntityEntry

var entity = context.Entry(objFromLocalLinqQuery);
var state = entity.Entry.State;

例如,您请求的功能作为Find方法的一部分存在,但不幸的是,由于一些未知的原因,它没有公开,他们认为它对他们没有用处,并且在发生异常时抛出异常

但由于EF核心代码是开源的,因此不难提取自定义扩展方法,该方法使用与Find内部实现类似的方法。的确,您可以搜索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版本中发生了更改,则可以/应该对其进行调整。如果你问我,与其浪费时间来创建代码分析器来显示这样的警告,不如让它们公开缺少的和有用的功能。无论如何,它就是它,我们应该利用它们提供给我们的功能。

例如,您所要求的功能是作为Find方法的一部分存在的,但不幸的是,由于一些未知的原因没有公开,他们认为它对他们没有用处,让我们在发生异常时抛出异常

但由于EF核心代码是开源的,因此不难提取自定义扩展方法,该方法使用与Find内部实现类似的方法。的确,您可以搜索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版本中发生了更改,则可以/应该对其进行调整。如果你问我,与其浪费时间来创建代码分析器来显示这样的警告,不如让它们公开缺少的和有用的功能。不管怎么说,这就是事实,我们应该利用他们给我们的东西。

回答不错,调试EF Core几个小时以找到更好的解决方案,不幸的是我们必须这样做。回答不错,调试EF Core几个小时以找到更好的解决方案,不幸的是我们必须这样做。