【问题标题】:Get DbContext from Entity in Entity Framework从实体框架中的实体获取 DbContext
【发布时间】:2014-08-10 15:20:32
【问题描述】:

我在 Visual Studio 的调试会话中深入业务层的某个地方,试图弄清楚为什么实体在尝试持久化更改时表现异常。

此时在调用堆栈中获取对该实体所属的 DbContext 的引用真的很有帮助。

即查看此实体的状态是什么(未更改、已修改等)。

所以我正在寻找这样的辅助方法:

var db_context = DbContextHelpers.GetDbContext(entity);

// after that I could do something like this
var state = db_context.Entry(entity);

我可以在调试期间在即时窗口中使用这些东西。

大家有什么建议吗?

补充说明

实体必须知道某处的DbContext,因为它正在使用它来延迟加载导航属性?

【问题讨论】:

  • 我对你的方法的正确性有些怀疑......如果你需要调试一些东西,你为什么不调试一些东西呢? .NET 有很好的工具(VS 中的调试器就是一个很好的例子)。此外,您可能想对单元测试进行一些研究,这也可能对您有所帮助..
  • 我正在调试@walther。我在调试会话中非常深入,我只需要获取我正在查看的模型的EntityState - 例如业务层深处的 12 层。它无法访问在代码的完全其他部分创建的 DbContext。
  • 如何设置一个 hack 来保存 DbContext 以便在您需要的地方可用?如果您正在开发 ASP.NET 应用程序,您可以将它放在 HttpContext.Current.Items 中或将其作为线程本地保存,您可以简单地将 DbContext 分配给某个静态类中的某个静态字段。在某些情况下,您可以在 VS 调试器的即时窗口中执行此操作,尤其是在HttpContext 中轻松完成。完成调试后,请务必删除 hack :-)。
  • @Dirk Boer 你是绝对正确的,但有时最好只做一些务实的事情。如果您更频繁地进行这种调试,您甚至可以自己编写一些帮助代码,自动保持对DbContext 的引用,并在您调试时启用它——例如通过 DI 或配置标志。我不确定是否可以为实体对象检索 DbContext,您可以使用 VS 调试器的监视功能深入研究该对象,也许您可​​以找到一些可以通过反射提取的参考。
  • 哇,@walther,很惊讶你怎么从这个问题中对我的架构了解这么多?听说过泄漏抽象吗? Entity Framework 绝对是其中之一,如果你做了一些现实生活中的高流量应用程序,你会发现不关心数据库的理论绝对不能完美地工作 - 有时你需要在调试会话中弄脏你的手看看发生了什么。

标签: c# entity-framework


【解决方案1】:
public static DbContext GetDbContextFromEntity(object entity)
{
    var object_context = GetObjectContextFromEntity( entity );

    if ( object_context == null )
        return null;

    return new DbContext( object_context, dbContextOwnsObjectContext: false );
}

private static ObjectContext GetObjectContextFromEntity(object entity)
{
    var field = entity.GetType().GetField("_entityWrapper");

    if ( field == null )
        return null;

    var wrapper  = field.GetValue(entity);
    var property = wrapper.GetType().GetProperty("Context");
    var context  = (ObjectContext)property.GetValue(wrapper, null);

    return context;
}

【讨论】:

  • 我用过这个,它在大多数情况下都有效。在一个项目中 entity.GetType().GetField("_entityWrapper") 返回 null,您知道可能的原因吗?
  • 嗯(还)没有发生在我身上。也许实体没有从 DbContext 包装或分离?就像你使用 AsNoTracking() 时一样?
  • @gillesemmanuel 如果不创建代理类,就会发生这种情况,例如如果您禁用了代理创建 stackoverflow.com/questions/24674310/… 或者您的实体类未满足代理类的要求 msdn.microsoft.com/en-us/library/dd468057(v=vs.100).aspx 等。
  • 这是金子!你可以把它放在一个超类中,或者用“Save”、“Find”、“Destroy”等为实体接口创建一组扩展方法,并将其用作私有方法(带有延迟加载)来创建一个“ ActiveRecord”之类的。想想可能性。
  • 请注意,返回的上下文可以被释放。因此,我更改了 GetDbContextFromEntity 中的空测试:var disposedField = typeof(ObjectContext).GetField("_disposed", BindingFlags.NonPublic | BindingFlags.Instance); if (object_context == null || (bool)disposedField.GetValue(object_context)) { return null; }。 (EF6)
【解决方案2】:

对于 EF6,我稍微修改了 Dirk 的回答:

    public static DbContext GetDbContextFromEntity(object entity)
    {
        var object_context = GetObjectContextFromEntity(entity);

        if (object_context == null || object_context.TransactionHandler == null)
            return null;

        return  object_context.TransactionHandler.DbContext;
    }

    private static ObjectContext GetObjectContextFromEntity(object entity)
    {
        var field = entity.GetType().GetField("_entityWrapper");

        if (field == null)
            return null;

        var wrapper = field.GetValue(entity);
        var property = wrapper.GetType().GetProperty("Context");
        var context = (ObjectContext)property.GetValue(wrapper, null);

        return context;
    }

没有 new DbContext() 并且它可以转换到您的主 Entities 类中。

注意:对于上述空返回值的问题,如果实体没有被保存/提交,就会发生这种情况。只能在 .Local 中找到的新实体似乎没有“_entityWrapper”字段。

【讨论】:

  • 我已将此添加为正确答案,比我原来的答案更好的解决方案
【解决方案3】:

我找到another way 来获取ObjectContext。不知道会不会好一点。

public static ObjectContext GetContext(this IEntityWithRelationships entity)
{
  if (entity == null)
    throw new ArgumentNullException("entity");

  var relationshipManager = entity.RelationshipManager;
  var relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault();

  if (relatedEnd == null)
    throw new Exception("No relationships found");

  var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
  if (query == null)
    throw new Exception("The Entity is Detached");

  return query.Context;
}

你可以像这样使用它:

MyContext context = myEntity.GetContext() as MyContext;

【讨论】:

    猜你喜欢
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    • 2017-06-15
    • 1970-01-01
    • 2013-12-26
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多