如何在 EF 中获取实体更改增量?

Posted

技术标签:

【中文标题】如何在 EF 中获取实体更改增量?【英文标题】:How to get entity change delta in EF? 【发布时间】:2011-12-14 17:44:03 【问题描述】:

我只需要获取已更改字段的列表,数据存储是 ssce,因此没有可用的触发器

EF 是否支持获取列表或构建通用组件?

【问题讨论】:

【参考方案1】:

根据上下文的类型和生成的实体,您可以通过几种不同的方式进行操作。 对于从 Entity 或 POCO 继承的对象,您可以使用 ObjectStateManager 如果是 Self-Tracking 实体,您可以使用实体本身的 Tracker。

请提供有关您如何生成上下文以及如何进行更改的更多详细信息

已编辑(2): 您可以像这样查询 ObjectStateManager 以获取更改的条目:

 var changed = ctx.ObjectStateManager.GetObjectStateEntries().Where(e=>e.State != EntityState.Unchanged);

已编辑(1):

MSDN 中的以下示例演示了如何查询更改:

int orderId = 43680;

using (AdventureWorksEntities context =
new AdventureWorksEntities())

var order = (from o in context.SalesOrderHeaders
             where o.SalesOrderID == orderId
             select o).First();

// Get ObjectStateEntry from EntityKey.
ObjectStateEntry stateEntry =
    context.ObjectStateManager
    .GetObjectStateEntry(((IEntityWithKey)order).EntityKey);

//Get the current value of SalesOrderHeader.PurchaseOrderNumber.
CurrentValueRecord rec1 = stateEntry.CurrentValues;
string oldPurchaseOrderNumber =
    (string)rec1.GetValue(rec1.GetOrdinal("PurchaseOrderNumber"));

//Change the value.
order.PurchaseOrderNumber = "12345";
string newPurchaseOrderNumber =
    (string)rec1.GetValue(rec1.GetOrdinal("PurchaseOrderNumber"));

// Get the modified properties.
IEnumerable<string> modifiedFields = stateEntry.GetModifiedProperties();
foreach (string s in modifiedFields)
    Console.WriteLine("Modified field name: 0\n Old Value: 1\n New Value: 2",
        s, oldPurchaseOrderNumber, newPurchaseOrderNumber);

// Get the Entity that is associated with this ObjectStateEntry.
SalesOrderHeader associatedEnity = (SalesOrderHeader)stateEntry.Entity;
Console.WriteLine("Associated Enity's ID: 0", associatedEnity.SalesOrderID);

【讨论】:

使用向导从 db 生成模型,典型代码 repo.entity.value = newvalue 进行更改 有趣,它是否可以扩展到多行,例如“表”是否绑定到网格并且用户对一行进行了更改,但我事先不知道是哪一个!!还是我需要为列表中的每条记录获取并存储 ObjectStateEntry(很容易有 > 10000 个条目) 您只能查询ObjectStateManager 进行更改 另一个故事是,如果在内存中加载了 10k 个实体,您可以对 Entity Framework 使用更复杂的方法,即在 OnChange 处理程序中将实体加载为分离的,将实体附加到上下文中,这将在上下文的ObjectStateManager 并且不要为整个 10k 集合的状态条目浪费资源。 还考虑研究可用于实体框架的扩展,例如在其之上构建的存储库,因为默认生成的上下文实现了工作单元模式并暗示相应地使用【参考方案2】:

使用数据库结构本身来执行此操作通常是一种很好的做法。 这只是您现在的另一种方法。

您可以在名为 ModifiedOn 的表中创建一个 datetime 类型的新字段,并在每次更新数据库中的行时更新它。

然后,当您希望在特定时间后更改行时,您只需使用:

where ModifiedOn > dateTime

这只是关于如何从不同角度解决问题的另一个建议。

【讨论】:

一般来说你甚至不需要手动更新字段,有专门的字段类型——时间戳。这种方法完全有道理,但它只允许您获得更改的时间。您仍然需要手动获取实际更改,您可以做的只是将原始记录与新记录一起保存或使用更复杂的方法,如查询日志(在 SQL Server 中)。另一方面,EntityFramework 在执行数据库更新之前已经保存了这些信息,因此使用这些现有数据是非常明显的决定 @vittore - 是的。我完全同意你的看法。我只是想指出,对于这个特殊问题,还有其他方法。

以上是关于如何在 EF 中获取实体更改增量?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 EF 核心在 SQLite 中创建自动增量列?

如何在 .SaveChanges() 期间首先使用 EF 代码记录所有实体更改?

如何在使用EF代码的.SaveChanges()期间记录所有实体更改?

如何在 EF Core 3.1 中使用脚手架流程更新我的实体 - 执行超时已过期

[小技巧]EF Core中如何获取上下文中操作过的实体

为什么使用T4修改EF中的实体?