简体   繁体   中英

Entity Framework not saving all properties on update

I am trying to update an entity with custom getters and setters but they are not being saved if I edit any other property on the entity. I have a DTO, which maps onto the retrieved entity.

DTO:

public class MyEntityDto
{
    public string Id { get; set; }

    public string Name { get; set; }

    public bool Enabled { get; set; }

    public Dictionary<string, string> Settings { get; set; }
}

Entity:

public class MyEntity
{
    public virtual Guid Id { get; set; }

    public virtual string Name { get; set; }

    public virtual bool Enabled { get; set; }

    public Dictionary<string, string> Settings { get; set; }

    public virtual string SettingsJson
    {
        get { return JsonConvert.SerializeObject(Settings); }
        set
        {
            Settings = JsonConvert.DeserializeObject<Dictionary<string, string>>(value);
        }
    }
}

Update Function:

public async Task UpdateAsync(dto MyEntityDto)
{
    var existingEntity = await _myRepository.GetByIdAsync(dto.Id);

    existingEntity.Name = dto.Name;
    existingEntity.Enabled = dto.Enabled;
    existingEntity.Settings = dto.Settings;

    await _myRepository.Update(existingEntity);

    // save changes happens at end of request
}

What happens is my SettingsJson does not get updated. I have stepped through it and existingEntity.SettingsJson and existingEntity.Settings both have the correct data. Name and Enabled do get updated.

However if I remove the assignments for Name and Enabled , SettingsJson does get updated.

It does work however on entity creation, just not on update. I would also like to point out I do not have access to DbContext .

  1. I'm guessing Entity Framework doesn't know it should update SettingsJson in the database because you never modify it directly in your code. Yes, you modify the Settings object which is used in the getter of SettingsJson , but Entity Framework does not track objects that way.

    Try this after modifying the Settings object, but before doing the actual update:

     _myDbContext.Entry(existingEntity).Property(e => e.SettingsJson).IsModified = true; 

    This code however assumes your DbContext is exposed, which may not be the case.

EDIT:

  1. If you don't have access to the DbContext , you must directly set the SettingsJson property in order to have Entity Framework update it in the database. I understand that in your current implementation you never need to worry about updating both the actual dictionary and the JSON representation of the dictionary, but that's just not possible with Entity Framework. You'll have to try something like this:

     public virtual string SettingsJson { get; set; } // just an auto-implemented property ... existingEntity.Settings = dto.Settings; existingEntity.SettingsJson = JsonConvert.SerializeObject(dto.Settings); // save changes 
  2. Another solution could be to directly set the SettingsJson in the setter of Settings , like so:

     private Dictionary<string, string> settings // private backing field public Dictionary<string, string> Settings { get { return settings; } set { settings = value; SettingsJson = JsonConvert.SerializeObject(dto.Settings); // EF tracks this } } 

    However , if you add elements to the dictionary after setting it, you need to re-serialize the dictionary again, in order to update the JSON string. You could solve this dynamically by using some sort of observable dictionary, but make sure it only serializes the dictionary once, when needed (before calling updating the database).

  3. This is not really a solution but it's food for thought. Databases don't understand dictionaries. You know that, that's why you're using JSON to help you out. However, why not simply add a Setting table to your database model?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM