实体框架 6:检测关系变化

2023-11-26

在我的 DbContext 子类中,我重写了 SaveChanges() 方法,因此我可以实现一种类似触发器的功能(在实际保存更改之前)。 现在,在其中一些触发器中,有必要检测某些关系是否发生了变化,无论是多对多、一对一/零等。

我在互联网上阅读了许多帖子,包括本网站上的一些帖子,其中提到 DbContext API 不公开任何获取关系信息的方法。 不过,ObjectContext 应该可以。

我的 SaveChanges 方法:

public override int SaveChanges()
{
    IEntity entity;
    ChangeTracker.DetectChanges();

    var stateManager = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager;
    var added = stateManager.GetObjectStateEntries(EntityState.Added).ToList();
    var updated = stateManager.GetObjectStateEntries(EntityState.Modified).ToList();
    var deleted = stateManager.GetObjectStateEntries(EntityState.Deleted).ToList();
    var unchanged = stateManager.GetObjectStateEntries(EntityState.Unchanged).ToList();

    while ((entity = _entitiesRequiringTriggering.FirstOrDefault(x => x.Value).Key) != null)
    {
        _entitiesRequiringTriggering[entity] = false;
        var entry = ChangeTracker.Entries<IEntity>().SingleOrDefault(x => x.State != EntityState.Unchanged && x.Entity == entity);
        if (entry == null) continue;
        var trigger = Triggers.Triggers.GetTriggerForEntity(entry.Entity, this);
        if (trigger == null) continue;
        trigger.BeforeSave(entry.Entity);
        switch (entry.State)
        {
            case EntityState.Added:
                trigger.BeforeAdd(entry.Entity);
                break;
            case EntityState.Modified:
                trigger.BeforeUpdate(entry.Entity);
                break;
            case EntityState.Deleted:
                trigger.BeforeDelete(entry.Entity);
                break;
        }
    }
    return base.SaveChanges();
}

注意四个变量added, updated, deleted and 不变。 根据我到目前为止所发现的,GetObjectStateEntries 应该返回一个 ObjectStateEntry 的集合,它有一个属性 IsRelationship。

我在测试应用程序中运行以下代码:

using (var db = container.Resolve<IDatabaseContext>())
{
    var cus = db.Query<Customer>().Single(x => x.Id == 1);
    var newAddress = db.Query<Address>().Single(x => x.Id == 5);

    cus.Address = newAddress; //also sets the foreign key property Customer.AddressId to its new corresponding value
    db.SaveChanges();
}

当我在调用后检查 SaveChanges 中的代码时,我得到了预期的结果: 一个结果是updated列表,客户对象。 但我从来没有获得过关系(一对一)Customer_Address 的 ObjectStateEntry。

我需要能够如前所述检测关系何时发生变化。 对于普通标量属性,您可以这样做:

var changed = DbEntry.Property(x => x.Name).OriginalValue == DbEntry.Property(x => x.Name).CurrentValue;

但对于参考属性来说,显然不起作用。 有任何想法吗?


你可以用这个ExtensionMethod获取已更改的关系列表

public static class DbContextExtensions
{
    public static IEnumerable<Tuple<object, object>> GetRelationships(
        this DbContext context)
    {
        return GetAddedRelationships(context)
                .Union(GetDeletedRelationships(context));
    }

    public static IEnumerable<Tuple<object, object>> GetAddedRelationships(
        this DbContext context)
    {
        return GetRelationships(context, EntityState.Added, (e, i) => e.CurrentValues[i]);
    }

    public static IEnumerable<Tuple<object, object>> GetDeletedRelationships(
        this DbContext context)
    {
        return GetRelationships(context, EntityState.Deleted, (e, i) => e.OriginalValues[i]);
    }

    private static IEnumerable<Tuple<object, object>> GetRelationships(
        this DbContext context,
        EntityState relationshipState,
        Func<ObjectStateEntry, int, object> getValue)
    {
        context.ChangeTracker.DetectChanges();
        var objectContext = ((IObjectContextAdapter)context).ObjectContext;

        return objectContext.ObjectStateManager
                            .GetObjectStateEntries(relationshipState)
                            .Where(e => e.IsRelationship)
                            .Select(
                                    e => Tuple.Create(
                                            objectContext.GetObjectByKey((EntityKey)getValue(e, 0)),
                                            objectContext.GetObjectByKey((EntityKey)getValue(e, 1))));
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实体框架 6:检测关系变化 的相关文章

随机推荐

  • Android Studio 无法与 HoloEverywhere 和 ActionBarSherlock 配合使用

    我能够将 ActionBarSherlock 和 HoloEverywhere 导入 Android Studio 但无法编译我的应用程序 截屏 https docs google com file d 0BwOn70drOiMfZHZVe
  • hibernate 4.3.x - 加载所有实体注释类

    在我从事的项目中 我不使用 Spring 仅使用 Hibernate 我不想使用 hbm xml 文件进行实体映射 描述 等 我只想使用注释 我如何告诉 Hibernate 加载所有内容Entity Table来自某些包的带注释的类 我在网
  • 在 Python 中实现可观察集合的推荐方法?

    我希望在 Python 中有一些可观察的集合 序列 让我能够监听更改事件 例如添加新项目或更新项目 list ObservableList a b c list addChangeListener lambda new value prin
  • 跨翻译单元和 gcc 4.6 自动内联函数

    如果我不将函数 f 声明为内联 如下 A h X f Y y A cpp X f Y y 然后在不同的翻译单元中 B cpp include A h Z g W w f 然后我用 gcc 4 6 编译两个翻译单元 A o 和 B o 然后也
  • 如何从控制器返回特定的状态代码并且没有内容?

    我希望下面的示例控制器返回没有内容的状态代码 418 设置状态代码很容易 但似乎需要做一些事情来表明请求结束 在 ASP NET Core 之前的 MVC 中或在 WebForms 中 可能会调用Response End 但它在 ASP N
  • C# 中的条件变量 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 C 中使用条件变量和监视器吗 有人能给我举个例子吗 与仅用于在 NET 中发出信号的条件变量等效的是抽象 WaitHandle 类 它的实际实现是 ManualResetEven
  • Xamarin Forms共享首选项交叉

    我想知道以跨平台方式操作应用程序设置的最佳解决方案是什么 在 iOS 中 我们可以在设置屏幕中更改应用程序外部的设置 但在 Windows Phone 和 Android 中则没有此功能 因此 我的想法是在应用程序内创建一个普通页面 屏幕
  • 用于开发 Flash 应用程序的最佳开源工具是什么?最好从哪些地方开始学习? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 就工具而言 我知道Haxe MTASC and swfmill 您能提供与其中任何一个相关的成功或恐怖故事吗 还有其他我应该调查的吗 在学习方面 Adobe 开发人员连接似乎包含不错的参考
  • 如何在 Three.js 中使用 gltf 模型投射阴影?

    嘿 我是三个 js 的新手 想知道如何用 gltf 模型投射阴影 我可以看到这是可能的 因为它正在工作here我假设我没有正确构建我的代码 var model new THREE GLTFLoader model load https th
  • Android Studio 测试显示测试结果 0/0。我怎样才能开始测试?

    我正在 Android Studio 中学习 Kotlin 初学者课程 在测试阶段 检测结果总是0 0 我怎样才能完成这些测试 代码由 Google Android 开发人员编写 应该可以完美运行 我用的是同样的 应用程序编译没有错误 代码
  • 应用程序特定的权限设置不授予本地激活权限

    我的一位同事建议我可以在 GPO 中修复此错误 它是 Windows 2016 服务器 The application specific permission settings do not grant Local Activation p
  • 画布不在自定义视图中绘制

    我创建了一个自定义视图 CircleView 如下所示 public class CircleView extends LinearLayout Paint paint1 public CircleView Context context
  • 停止从 selenium webdriver 加载浏览器

    我的 selenium webdriver 转到一个页面并等待该页面完成加载 如果超过 30 秒 则会超时并且脚本失败 有没有办法让网络驱动程序在 30 秒后停止页面加载 比如按浏览器上的 x 这将防止我的驱动程序超时 我正在使用 Chro
  • 将文件发送到回收站

    目前我正在使用以下功能 file Delete 但是如何使用此函数将文件发送到回收站而不是直接删除它呢 Use 文件系统 删除文件并指定正确的回收选项 虽然这适用于 UI 交互式应用程序 但它不适用于非 UI 交互式应用程序 例如 Wind
  • 在类定义之外定义方法?

    class MyClass def myFunc self pass 我可以创建吗MyFunc 在类定义之外 甚至可能在另一个模块中 是的 您可以在类外部定义函数 然后在类主体中将其用作方法 def func self print func
  • Spring-boot调度器在没有@EnableScheduling注解的情况下运行

    我按照此示例在示例项目中创建计划任务 https spring io guides gs scheduling tasks 它说 EnableScheduling ensures that a background task executo
  • ChromeOptions 使用 Selenium ChromeDriver for node.js 导致引用错误

    我正在尝试使用 Selenium 的 ChromeDriver 驱动程序来使用 Chrome 运行一些测试 但是当我使用时出现引用错误ChromeOptions My Code 我想强制使用某些选项 例如针对特定的用户配置文件进行测试 基于
  • 八度向量解包

    Octave matlab 用于处理多个返回值的表示法 a b f x 表明 f x 返回的值是一种行向量 并且 Octave 支持向量解包 就像 Python 的元组解包 然而当我把 a b 1 2 I get 错误 常量表达式的输出参数
  • PHP 脚本被杀死且没有任何解释

    我按以下方式启动我的 php 脚本 bash cd path php f scriptname php php 脚本运行时没有任何输出 一段时间后 php 脚本响应 Killed 我的想法是它达到了内存限制 ini set memory l
  • 实体框架 6:检测关系变化

    在我的 DbContext 子类中 我重写了 SaveChanges 方法 因此我可以实现一种类似触发器的功能 在实际保存更改之前 现在 在其中一些触发器中 有必要检测某些关系是否发生了变化 无论是多对多 一对一 零等 我在互联网上阅读了许