Entity framework not detecting jsonb properties changes in c#

Viewed 1865

I am using Entity Framework Core with npgsql postgresql for Entity Framework Core. and i'm working with .net core 3

My question is, when i try to update a MyTableRelated element from the MyTableClass and saving the context to the database, no changes are detected.

For example, lets suppose we have the following classes:

public class MyTableClass
{
    public int Id { get; set; }

    [Column(TypeName = "jsonb")]
    public virtual List<MyTableRelated> Data { get; set; }
}

public class MyTableRelated
{
    public int Id { get; set; }

    public string prop1 { get; set; }

    public string prop2 { get; set; }
}

and some code like this (this is not actual code, its just to get the ideia):

var context = dbContext;

var newMyTableClass = new MyTableClass() {
    Id = 1;
};

var newMyTableRelated = new MyTableRelated(){
    Id=1;

    prop1 = "";

    prop2 = "";
}

newMyTableClass.Data.Add(newMyTableRelated);

context.SaveChanges();

This works, and the entry is saved on the database.

Now somewhere on the application, i want to access that entry and change values on Data:

var context = dbContext;

var updateMyTableClass = context.MyTableClass.FirstOrDefault(x => x.Id == 1);

var tableRelated = updateMyTableClass.Data.FirstOrDefault(y => y.Id == 1);

tableRelated.prop1 = "prop1";

tableRelated.prop2 = "prop2";

context.SaveChanges();

I would suppose this would change values on database, like it does for other types of properties. But nothing happens.

A solution i found, was using this:

var entry = context.Entry(updateMyTableClass);
if (entry.State == EntityState.Unchanged)
{
   entry.State = EntityState.Modified;
}

This is more of a temporary solution for that case.

How can we then make the EF automatically detect changes on jsonb properties?

Someone pointed to me that i should look at coase grained lock. https://www.martinfowler.com/eaaCatalog/coarseGrainedLock.html

How can something like that be implemented?

1 Answers

Automatic change detection would mean that EF Core would take a snapshot of the JSON document when it loads the property (duplicating the entire tree), and then do a complete structural comparison of the original and current tree whenever SaveChanges is called. As this can be very heavy perf-wise, it is not done by default.

However, if you wish to do so, you can create a value comparer to implement precisely this - see the EF docs on how to do that. I've opened an issue on the Npgsql provider repo in case someone wishes to contribute this.

For perf reasons, I'd recommend manually flagging properties when they change, similar to what you have done. Note that you're marking the entire entity instance as changed - so all properties will be saved. You can use the following to only mark the JSON property:

ctx.Entry(entry).Property(e => e.SomeJsonProperty).IsModified = true;
Related