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
.
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:
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
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).
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?