Using ChangeTracker - adamfoneil/Dapper.CX GitHub Wiki

Use ChangeTracker as an optional argument with Save*, Update* and Merge* methods to update changed properties only. ChangeTracker<T> has no effect during inserts. Here's a simple usage. Some context has been omitted to keep the example short:

var emp = await cn.GetAsync<Employee>(id);
var ct = new ChangeTracker<Employee>(emp);

emp.Type = "whatever";
emp.IsExempt = false;

await cn.SaveAsync(emp, ct);

In this example, only the Type and IsExempt properties will be affected by the update. I like using this when I want to be sure that updates don't touch columns unnecessarily.

You can go a step further and log ChangeTracker<T> instances to keep a persistent history of all updates for all users. This requires an additional Nuget package Dapper.CX.ChangeTracking. The next section describes this.

Using Dapper.CX.ChangeTracking

Note: I've retired this package, and am working on new documentation for using the [TrackChanges] attribute


Nuget

To log changes in your database to a table, install package Dapper.CX.ChangeTracking, and use LoggedChangeTracker instead of the regular ChangeTracker<T>. The first time you use LoggedChangeTracker<T> it will create two tables in your database under a changes schema: RowVersion and ColumnHistory.

Use LoggedChangeTracker<T> almost exactly as you would an ordinary ChangeTracker<T>. The difference is that you must pass a user name that the current changes are done by, and you must use the async crud methods SaveAsync, UpdateAsync, or MergeAsync that accept a ChangeTracker<T> argument. (Sync methods are not supported.) Adapting the example above from an integration test from the repo, it would look like this for the user adamo:

var emp = new Employee()
{
    LastName = "Herbert",
    FirstName = "Yavad",
    HireDate = new DateTime(1990, 1, 1),
    IsExempt = true,
    Status = Status.Active
};
await cn.SaveAsync(emp);
var ct = new LoggedChangeTracker<Employee>("adamo", emp);

emp.FirstName = "Javad";
emp.Status = Status.Inactive;
await cn.SaveAsync(emp, ct);

You can then query the changes.ColumnHistory table, and it would look like this:

img

For key columns that you want to convert to text when changes are logged, implement interface ITextLookup on your model class. See example here. The integration test shows how the Price and TypeId properties of a model are updated. TypeId is a key column that is translated to a text value when changes are logged. After running the test, you see that the TypeId shows the text values this and other instead of the numeric Ids. A change in the Price property is also logged.

var ids = new HashSet<int>();
Array.ForEach(new[] { "this", "that", "other" }, (name) =>
{
    ids.Add(await cn.SaveAsync(new WidgetType() { Name = name }));
});

var w = new Widget()
{
    Description = "this new thing",
    TypeId = ids.First(),
    Price = 23.4m
};

int widgetId = await cn.SaveAsync(cn, w);
var ct = new LoggedChangeTracker<Widget>("adamo", w);

w.Price = 21.7m;
w.TypeId = ids.Last();
await cn.SaveAsync(w, ct);

img

⚠️ **GitHub.com Fallback** ⚠️