Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get entity change delta in EF?

I need to get the list of changed fields only, the datastore is ssce so no triggers are available

Is there any support in EF to get a list or to build a generic component ?

like image 709
Kumar Avatar asked Dec 14 '11 17:12

Kumar


People also ask

How does EF core detect changes?

By default, EF Core creates a snapshot of every entity's property values when it is first tracked by a DbContext instance. The values stored in this snapshot are then compared against the current values of the entity in order to determine which property values have changed.

How does Entity Framework keep track of changes?

EF Core change tracking works best when the same DbContext instance is used to both query for entities and update them by calling SaveChanges. This is because EF Core automatically tracks the state of queried entities and then detects any changes made to these entities when SaveChanges is called.


2 Answers

Depending on the type of context and generated entities you can do it in several different ways. In case of objects inherited from Entity or POCO you can use ObjectStateManager in case of Self-Tracking entities you can use Tracker from entity itself.

please provide more details on the way how you generated context and how you make changes

EDITED(2): you can query ObjectStateManager for changed entries simply like this:

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

EDITED(1):

The following example from MSDN demonstrate how to query for changes:

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);
}
like image 52
vittore Avatar answered Oct 12 '22 19:10

vittore


It's commonly a good practice to do this by using the database structure itself. This is just another approach to the one you have now.

You can create a new field of type datetime in a table called for example ModifiedOn and update it every time that you update the row in the database.

Then when you want the changed rows after a specific time you just use:

where ModifiedOn > dateTime

It's just another suggestion on how you can approach the problem from a different angle.

like image 45
TheBoyan Avatar answered Oct 12 '22 19:10

TheBoyan