Update parent and child collections on generic repository with EF Core

后端 未结 3 580
醉话见心
醉话见心 2020-12-29 14:14

Say I have a Sale class:

public class Sale : BaseEntity //BaseEntity only has an Id  
{        
    public ICollection Items { get;          


        
3条回答
  •  自闭症患者
    2020-12-29 15:09

    @craigmoliver Here's my solution. It is not the best, I know - if you find a more elegant way, please share.

    Repository:

    public async Task UpdateAsync(TEntity entity, bool save = true, params Expression>[] navigations)
                where TEntity : class, IIdEntity
            {
                TEntity dbEntity = await _context.FindAsync(entity.Id);
    
            EntityEntry dbEntry = _context.Entry(dbEntity);
            dbEntry.CurrentValues.SetValues(entity);
    
            foreach (Expression> property in navigations)
            {
                var propertyName = property.GetPropertyAccess().Name;
                CollectionEntry dbItemsEntry = dbEntry.Collection(propertyName);
                IClrCollectionAccessor accessor = dbItemsEntry.Metadata.GetCollectionAccessor();
    
                await dbItemsEntry.LoadAsync();
                var dbItemsMap = ((IEnumerable)dbItemsEntry.CurrentValue)
                    .ToDictionary(e => string.Join('|', _context.FindPrimaryKeyValues(e)));
    
                foreach (var item in (IEnumerable)accessor.GetOrCreate(entity))
                {
                    if (!dbItemsMap.TryGetValue(string.Join('|', _context.FindPrimaryKeyValues(item)), out object oldItem))
                    {
                        accessor.Add(dbEntity, item);
                    }
                    else
                    {
                        _context.Entry(oldItem).CurrentValues.SetValues(item);
                        dbItemsMap.Remove(string.Join('|', _context.FindPrimaryKeyValues(item)));
                    }
                }
    
                foreach (var oldItem in dbItemsMap.Values)
                {
                    accessor.Remove(dbEntity, oldItem);
                    await DeleteAsync(oldItem as IEntity, false);
    
                }
            }
    
            if (save)
            {
                await SaveChangesAsync();
            }
    
            return entity;
        }
    
    
    

    Context:

     public IReadOnlyList FindPrimaryKeyProperties(T entity)
            {
                return Model.FindEntityType(entity.GetType()).FindPrimaryKey().Properties;
            }
    
            public IEnumerable FindPrimaryKeyValues(TEntity entity) where TEntity : class
            {
                return from p in FindPrimaryKeyProperties(entity)
                       select entity.GetPropertyValue(p.Name);
            }
    
        

    提交回复
    热议问题