我目前正在开发一个ASP.NET Core Web API.当用户正在查看的实体发生更改时,需要通知客户端更新其数据.

为此,我需要检测何时对特定父实体进行了更改.我通过判断在覆盖上下文的SaveChanges方法时是否将Entry(Parent).State设置为任何值而不是未更改来完成此操作:

public override int SaveChanges()
{
    foreach(var p in Parents)
    {
        if (Entry(p).State != EntityState.Unchanged)
        {
            // Notify client
        }
    }

    return base.SaveChanges()
}

我的问题是,如果任何子对象发生更改,我还需要告诉客户端进行更新,但我似乎找不到一种方法来检测这一点.

S的Entry‘属性(Entry().Properties.Navigations等)都将子项显示为IsModified == false,而更改跟踪器似乎也没有帮助.

编辑:我可以判断更改跟踪器的Entries,并查看我正在查找的Parent的ID是否设置为修改后的子项的外键,但我还需要能够检测子项的子项是否更改.如果与Parent相关的任何内容发生更改,客户端需要更新其视图.

百龙的回答非常有帮助,尽管我不得不做了几处改动才能让它正常工作.我目前不能try 所有可能的情况,因为在编写本文时,API还没有完成,但就我测试的情况而言,它是有效的.它可能有点低效率或有错误,但对于任何寻找相同东西的人来说,它应该是一个足够的指针:

private void DetectAndNotifyChanges()
{
    foreach(var p in Parents)
    {
        var pEntry = Entry(p);
        if (pEntry.State != EntityState.Unchanged || HasChangesInChildren(p))
        {
            // Notify client
        }
    }
}

对于DetectAndNotifyChanges,我判断每个父对象,并通知受更改影响的对象.

private List<dynamic> checkedEntries = new List<dynamic>();

private bool HasChangesInChildren(dynamic parent)
{
    foreach(var navigationEntry in Entry(parent).Navigations)
    {
        if (navigationEntry is CollectionEntry collectionEntry)
        {
            collectionEntry.Load();
            foreach(var child in collectionEntry.CurrentValue)
            {
                var childEntry = Entry(child);
                if (!checkedEntries.Contains(childEntry))
                {
                    checkedEntries.Add(childEntry);

                    if (childEntry.State != EntityState.Unchanged || HasChangesInChildren(child))
                    {
                        return true;
                    }
                }
            }
        }
        else if (navigationEntry is ReferenceEntry referenceEntry)
        {
            referenceEntry.Load();
            dynamic childEntry = referenceEntry.EntityEntry;

            if (!checkedEntries.Any(x => x.GetType() == childEntry.GetType() && x.Entity.Id == childEntry.Entity.Id))
            {
                checkedEntries.Add(childEntry);
                if (childEntry.State != EntityState.Unchanged || HasChangesInChildren(childEntry.Entity))
                {
                    return true;
                }
            }
        }
    }

    return false;
}

然后,对于HasChangesInChildren,我将参数更改为Dynamic,因为它先判断父对象,然后判断子对象,然后再判断子对象,等等,为referenceEntrycollectionEntry添加Load,因为它们以前没有加载,并且通过排除任何以前判断过的对象来防止无限递归,使用checkedEntries列表再次判断.

推荐答案

 public override int SaveChanges()
{
    DetectAndNotifyChanges();
    return base.SaveChanges();
}

private void DetectAndNotifyChanges()
{
    foreach (var entry in ChangeTracker.Entries())
    {
        if (entry.State == EntityState.Modified)
        {
            if (entry.Entity is Parent parent)
            {
                if (HasChangesInChildren(parent))
                {
                    // Notify client about changes in parent or children
                }
            }
        }
    }
}

private bool HasChangesInChildren(Parent parent)
{
    foreach (var navigationEntry in Entry(parent).Navigations)
    {
        if (navigationEntry is CollectionEntry collectionEntry)
        {
            foreach (var child in collectionEntry.CurrentValue)
            {
                var childEntry = Entry(child);
                if (childEntry.State != EntityState.Unchanged || HasChangesInChildren(child))
                {
                    return true;
                }
            }
        }
        else if (navigationEntry is ReferenceEntry referenceEntry)
        {
            var childEntry = referenceEntry.TargetEntry;
            if (childEntry.State != EntityState.Unchanged || HasChangesInChildren(childEntry.Entity as Parent))
            {
                return true;
            }
        }
    }

    return false;
}

递归地遍历子实体,并针对每个实体判断其EntityState,如果任何子实体有更改,则将父实体标记为已修改.

Csharp相关问答推荐

获取Windows和Linux上的下载文件夹

有没有方法让ASP.NET Core模型绑定器使用私有设置器来设置属性?

Blazor:用参数创建根路径

C#相同名称的枚举方法和normal方法,参数类型不同

如何将Kafka消息时间戳转换为C#中的日期和时间格式?

MAUI查询参数单一字符串项将不起作用

从应用程序图API调用访问所有者字段

MongoDB.NET-将数据绑定到模型类,但无法读取整数值

.NET 6控制台应用程序,RabbitMQ消费不工作时,它的程序文件中的S

如何解决提交按钮后 Select 选项错误空参照异常

异步任务导致内存泄漏

在IAsyncEnumerable上先调用,然后跳过(1)可以吗?

CA1508:';NULL=>;TRUE;始终为';TRUE';.移除或重构条件(S)以避免死代码

具有以接口为其类型的属性的接口;类指定接口的实现,但无效

Lambda表达式如何与隐式强制转换一起工作?

为什么ReadOnlySpan;T&>没有Slice(...)的重载接受Range实例的?

如何使用Npgsql从SELECT获得所有查询结果

用于ASP.NET核心的最小扩展坞

C#System.Commandline:如何向命令添加参数以便向其传递值?

如何保存具有多个重叠图片框的图片框?