代码之家  ›  专栏  ›  技术社区  ›  atiyar

使用泛型方法更新一对一父/子

  •  0
  • atiyar  · 技术社区  · 4 年前

    我遇到了 this question ,并喜欢如何实现一对多的通用更新。

    我试图模仿它来为自己实现一对一的版本,但没有完全成功。下面是我奋斗的结果-

    public async Task<int> UpdateAsync<T>(T entity, params Expression<Func<T, object>>[] navigations) where T : EntityBase
    {
        var dbEntity = await _DbCtx.FindAsync<T>(entity.Id);
    
        var entry = _DbCtx.Entry(dbEntity);
        entry.CurrentValues.SetValues(entry);
    
        foreach (var nav in navigations)
        {
            string propertyName = nav.GetPropertyAccess().Name;        
            
            // Problem #01 //
            // if possible, I'd like to avoid this reflection in favor of EF Core MetaData?
            var child = (EntityBase)entity.GetType().GetProperty(propertyName).GetValue(entity);
            if (child == null)
                continue;            // if the client-sent model doesn't have child, skip
    
            var referenceEntry = entry.Reference(propertyName);
            await referenceEntry.LoadAsync();
    
            var dbChild = (EntityBase)referenceEntry.CurrentValue;
            if (dbChild == null)
            {
                // Problem #02 //
                // if the existing entity doesn't have child, the client-sent child will be assigned.
                // but I could not figure out how to do this
            }
            else
            {
                _DbCtx.Entry(dbChild).CurrentValues.SetValues(child);
            }
        }
    
        return await _DbCtx.SaveChangesAsync();
    }
    

    我已将这些问题标记为 Problem #01 Problem #02 在上面的代码注释中。如有任何建议,解决方案将不胜感激。谢谢。


    或者,如果你认为有一个更好的,更有效的方法做同样的事情,我正试图做上述,请分享你的知识。

    0 回复  |  直到 4 年前
        1
  •  1
  •   R. Zanel    4 年前

    GetCollectionAccessor ,但有一种方法我可以用 EF Core Entry 断开连接的实体中的方法:

    var entry = _context.Entry(dbEntity);
    entry.CurrentValues.SetValues(entry);
    
    var disconnectedEntry = _context.Entry(entity); // new
    
    foreach (var nav in navigations)
    {
        string propertyName = nav.GetPropertyAccess().Name;
        var navigationChild = disconnectedEntry.Navigation(propertyName).CurrentValue; // new
    }
    

    记住,在每一个 进入 方法调用 将尝试检测变化。由于此实体不需要此验证,因此可以在禁用 AutoDetectChanges 作为 suggested in this issue .

    现在是问题02 Entity ReferenceEntry

            var referenceEntry = entry.Reference(propertyName);
            await referenceEntry.LoadAsync();
    
            var dbChild = (EntityBase)referenceEntry.CurrentValue;
            if (dbChild == null)
            {
               referenceEntry.CurrentValue = navigationChild; // new
            }
            else
            {
                _DbCtx.Entry(dbChild).CurrentValues.SetValues(child);
            }
    

    我希望它能帮助你。如果有什么问题,请告诉我!

    编辑

    我也建议你读一下 TrackGraph method