Entity Framework 更新时不保存所有属性

Entity Framework not saving all properties on update

我正在尝试使用自定义 getter 和 setter 更新实体,但如果我编辑实体上的任何其他 属性,它们将不会被保存。我有一个 DTO,它映射到检索到的实体。

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; }
}

实体:

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);
        }
    }
}

更新函数:

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
}

我的 SettingsJson 没有更新。我已经完成了它并且 existingEntity.SettingsJsonexistingEntity.Settings 都有正确的数据。 NameEnabled 会更新。

但是,如果我删除 NameEnabled 的分配,SettingsJson 会得到更新。

它确实适用于实体创建,但不适用于更新。我还想指出我无权访问 DbContext.

  1. 我猜 Entity Framework 不知道它应该在数据库中更新 SettingsJson,因为您永远不会在代码中直接修改它。是的,您修改了 SettingsJson 的 getter 中使用的 Settings 对象,但是 Entity Framework 不会那样跟踪对象。

    在修改 Settings 对象之后尝试此操作,但在进行实际更新之前:

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

    然而,此代码假定您的 DbContext 已暴露,但事实可能并非如此。

编辑:

  1. 如果你没有权限访问DbContext,你必须直接设置SettingsJson属性为了让 Entity Framework 在数据库中更新它。我知道在您当前的实现中,您永远不需要担心更新实际字典和字典的 JSON 表示,但是 Entity Framework 不可能做到这一点。你必须尝试这样的事情:

    public virtual string SettingsJson { get; set; } // just an auto-implemented property
    
    ...
    
    existingEntity.Settings = dto.Settings;
    existingEntity.SettingsJson = JsonConvert.SerializeObject(dto.Settings);
    // save changes
    
  2. 另一个解决方案可以直接在Settings的setter中设置SettingsJson,像这样:

    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
        }
    }
    

    但是,如果在设置后向字典添加元素,则需要重新序列化字典,才能更新JSON字符串。您可以通过使用某种可观察字典来动态解决此问题,但请确保它仅在需要时(在调用更新数据库之前)将字典序列化一次。

  3. 这不是真正的解决方案,但值得深思。数据库不理解字典。你知道的,这就是你使用 JSON 来帮助你的原因。但是,为什么不简单地添加一个 Setting table 到你的数据库模型呢?