public static ValueTask <int> RelationalUpdateAsync <T>(this DbContext context, T entity) where T : class
        {
            var configuration = new RelationalUpdateConfiguration
            {
                UpdatedTypes = context.Entry(entity).GetCollectionTypes()
            };

            return(RelationalUpdateAsync(context, entity, configuration));
        }
        public static async ValueTask <int> RelationalUpdateAsync <T>(this DbContext context, T entity, RelationalUpdateConfiguration configuration) where T : class
        {
            var entry      = context.Entry(entity);
            var primaryKey = entry.GetPrimaryKeyValue();
            var navigation = entry.Metadata.GetNavigations().ToList();

            foreach (var collectionType in configuration.UpdatedTypes)
            {
                var propertyName = navigation.Where(p => p.ClrType.GetFirstGenericArgument() == collectionType.Type).Select(p => p.Name).FirstOrDefault();
                if (string.IsNullOrEmpty(propertyName))
                {
                    continue;
                }
                var collection = entry.Collection(propertyName);

                var foreignKey     = collection.Metadata.ForeignKey;
                var primaryKeyName = collection.EntityEntry.GetPrimaryKeyName();

                var collectionValues = (IEnumerable <dynamic>)entity.GetType().GetProperty(propertyName)?.GetValue(entity, null);
                var dynamicList      = (collectionValues ?? throw new InvalidOperationException()).ToDynamicList();
                var currentIds       = dynamicList.Select(p => p.GetType().GetProperty(primaryKeyName)?.GetValue(p, null))
                                       .ToList();

                var fkName         = foreignKey.Properties.FirstOrDefault()?.Name;
                var databaseValues = await context.Query(collectionType.Type)
                                     .AsQueryable()
                                     .Where($"{fkName} == @0", primaryKey)
                                     .ToDynamicListAsync();

                var databaseIds = databaseValues
                                  .Select(p => p.GetType().GetProperty(primaryKeyName)?.GetValue(p, null))
                                  .ToList();
                if (collectionType.RemoveDataInDatabase)
                {
                    var deletedItems = databaseValues.Where(p =>
                                                            currentIds.Contains(p.GetType().GetProperty(primaryKeyName)?.GetValue(p, null)) == false)
                                       .ToList();
                    context.RemoveRange(deletedItems);
                }
                foreach (dynamic o in dynamicList)
                {
                    var id = o.GetType().GetProperty(primaryKeyName)?.GetValue(o, null);
                    if (databaseIds.Contains(id))
                    {
                        context.Entry(o).State = EntityState.Modified;
                    }
                    else
                    {
                        o.GetType().GetProperty(fkName)?.SetValue(o, primaryKey, null);
                        context.Entry(o).State = EntityState.Added;
                    }
                }
            }
            if (configuration.TriggerSaveChanges)
            {
                return(await context.SaveChangesAsync());
            }

            return(0);
        }