Fields not marked as modified are updating using the Attach method in entityframeworkcore

c# entity-framework-core

Question

I am trying to update a record using Entityframework core context. I need to update just three fields but even setting isModified property on one modifies the other two as well. I am using the Attach method as what I understood from the the documentation is that Attach is preferable when you use few fields over update. Here is my code. Could some body tell me how the other two fields that are not marked as isModified = true is updating.

Model

public class UserAgreement
    {
        public long ID { get; set; }

        public int UserID { get; set; }

        public int AgreementID { get; set; }

        public int? UserAgreementStateID { get; set; }

        public DateTime? AcceptanceWindowExpiry { get; set; }

        public string CreatedBy { get; set; }

        public DateTime Created { get; set; }

        public string ModifiedBy { get; set; }

        public DateTime Modified { get; set; }

        public DateTime RecordStartDateTime { get; set; }

        public DateTime RecordEndDateTime { get; set; }
    }



   public void UpdateUserAgreements(long userAgreementId, string userId, string state)
    {
        var userAgreement = _context.UserAgreement.Where(x => x.ID == userAgreementId).Select(x => x)
            .FirstOrDefault();

        if (userAgreement != null)
        {
            userAgreement.UserAgreementStateID = GetAgreementStateId(state);
            userAgreement.ModifiedBy = userId;
            userAgreement.Modified = DateTime.UtcNow;

            _context.Attach(userAgreement);
            _context.Entry(userAgreement).Property("UserAgreementStateID").IsModified = true; 
           // _context.UserAgreement.Update(userAgreement);
            _context.SaveChanges();
        }
    }
1
1
3/2/2020 5:55:02 PM

Popular Answer

All explicit state related methods/properties (Attach, Update, State, IsModified) apply mainly in the so called Disconnected entities scenario, as explained in the documentation link:

However, sometimes entities are queried using one context instance and then saved using a different instance. This often happens in "disconnected" scenarios such as a web application where the entities are queried, sent to the client, modified, sent back to the server in a request, and then saved. In this case, the second context instance needs to know whether the entities are new (should be inserted) or existing (should be updated).

However, what you are using is the "connected" approach (load/modify/save), also explained at the beginning of the documentation link:

A DbContext instance will automatically track entities returned from the database. Changes made to these entities will then be detected when SaveChanges is called and the database will be updated as needed.

So, when you do

var userAgreement = _context.UserAgreement.Where(x => x.ID == userAgreementId).Select(x => x)
    .FirstOrDefault();

the userAggreement entity is retrieved from the database and is tracked by the context, which means Attach has no effect (it's already attached), and also change tracker has the original (database) values of the properties. Hence when you change some property value, the property (and the entity) is automatically marked as Modified. If the values you are setting are the same as the original, then the property (and even the entity if all values are the same as the original) won't be updated.

Hence your code is doing the same as

var userAgreement = _context.UserAgreement
    .FirstOrDefault(x => x.ID == userAgreementId);

if (userAgreement != null)
{
    userAgreement.UserAgreementStateID = GetAgreementStateId(state);
    userAgreement.ModifiedBy = userId;
    userAgreement.Modified = DateTime.UtcNow;

    _context.SaveChanges();
}

SaveChanges will execute UPDATE command only if any of the UserAgreementStateID, ModifiedBy and Modified property values are different from the original, and also the UPDATE command will include only the modified columns/values.

Since this is a "smart" update, you can even optimizations like this:

userAgreement.UserAgreementStateID = GetAgreementStateId(state);
if (_context.Entry(userAgreement).Property(e => e.UserAgreementStateID).IsModified)
// or if (_context.Entry(userAgreement).State == EntityState.Modified)
{
    userAgreement.ModifiedBy = userId;
    userAgreement.Modified = DateTime.UtcNow;
    _context.SaveChanges();
}
1
3/2/2020 6:42:51 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow