private async Task <object> ExecAndReturnResponseAsync <Table>(object dto, IDbConnection db, Func <ExecContext, Task <ExecValue> > fn) { var responseType = HostContext.Metadata.GetOperation(dto.GetType())?.ResponseType; var responseProps = responseType == null ? null : TypeProperties.Get(responseType); var idProp = responseProps?.GetAccessor(Keywords.Id); var countProp = responseProps?.GetAccessor(Keywords.Count); var resultProp = responseProps?.GetAccessor(Keywords.Result); var rowVersionProp = responseProps?.GetAccessor(Keywords.RowVersion); var execValue = await fn(new ExecContext(idProp, resultProp, countProp, rowVersionProp)); if (responseType == null) { return(null); } object idValue = null; var response = responseType.CreateInstance(); if (idProp != null && execValue.Id != null) { idValue = execValue.Id.ConvertTo(idProp.PropertyInfo.PropertyType); idProp.PublicSetter(response, idValue); } if (countProp != null && execValue.RowsUpdated != null) { countProp.PublicSetter(response, execValue.RowsUpdated.ConvertTo(countProp.PropertyInfo.PropertyType)); } if (resultProp != null && execValue.Id != null) { var result = await db.SingleByIdAsync <Table>(execValue.Id); resultProp.PublicSetter(response, result.ConvertTo(resultProp.PropertyInfo.PropertyType)); } if (rowVersionProp != null) { if (AutoMappingUtils.IsDefaultValue(idValue)) { var modelDef = typeof(Table).GetModelMetadata(); var dtoIdGetter = TypeProperties.Get(dto.GetType()).GetPublicGetter(modelDef.PrimaryKey.Name); if (dtoIdGetter != null) { idValue = dtoIdGetter(dto); } } if (AutoMappingUtils.IsDefaultValue(idValue)) { throw new NotSupportedException($"Could not resolve Primary Key from '{dto.GetType().Name}' to be able to resolve RowVersion"); } var rowVersion = await db.GetRowVersionAsync <Table>(idValue); rowVersionProp.PublicSetter(response, rowVersion.ConvertTo(rowVersionProp.PropertyInfo.PropertyType)); } return(response); }
private async Task <object> UpdateInternalAsync <Table>(object dto, bool skipDefaults) { using var db = AutoQuery.GetDb <Table>(Request); using (Profiler.Current.Step("AutoQuery.Update")) { var response = await ExecAndReturnResponseAsync <Table>(dto, db, async ctx => { var dtoValues = ResolveDtoValues(dto, skipDefaults); var pkFieldDef = typeof(Table).GetModelMetadata()?.PrimaryKey; if (pkFieldDef == null) { throw new NotSupportedException($"Table '{typeof(Table).Name}' does not have a primary key"); } if (!dtoValues.TryGetValue(pkFieldDef.Name, out var idValue) || AutoMappingUtils.IsDefaultValue(idValue)) { throw new ArgumentNullException(pkFieldDef.Name); } // Should only update a Single Row var rowsUpdated = GetAutoFilterExpressions(db, dto, dtoValues, Request, out var expr, out var exprParams) ? await db.UpdateOnlyAsync <Table>(dtoValues, expr, exprParams.ToArray()) : await db.UpdateOnlyAsync <Table>(dtoValues); if (rowsUpdated != 1) { throw new OptimisticConcurrencyException($"{rowsUpdated} rows were updated by '{dto.GetType().Name}'"); } return(new ExecValue(idValue, rowsUpdated)); }); //TODO: UpdateOnly return(response); } }
private Dictionary <string, object> ResolveDtoValues(object dto, bool skipDefaults = false) { var dtoValues = dto.ToObjectDictionary(); var meta = AutoCrudMetadata.Create(dto.GetType()); if (meta.MapAttrs != null) { foreach (var entry in meta.MapAttrs) { if (dtoValues.TryRemove(entry.Key, out var value)) { dtoValues[entry.Value.To] = value; } } } var appHost = HostContext.AppHost; if (skipDefaults || meta.UpdateAttrs != null || meta.DefaultAttrs != null) { List <string> removeKeys = null; Dictionary <string, object> replaceValues = null; foreach (var entry in dtoValues) { var isNullable = meta.NullableProps?.Contains(entry.Key) == true; var isDefaultValue = entry.Value == null || (!isNullable && AutoMappingUtils.IsDefaultValue(entry.Value)); if (isDefaultValue) { var handled = false; if (meta.DefaultAttrs != null && meta.DefaultAttrs.TryGetValue(entry.Key, out var defaultAttr)) { handled = true; replaceValues ??= new Dictionary <string, object>(); replaceValues[entry.Key] = appHost.EvalScriptValue(defaultAttr, Request); } if (!handled) { if (skipDefaults || (meta.UpdateAttrs != null && meta.UpdateAttrs.TryGetValue(entry.Key, out var attr) && attr.Style == AutoUpdateStyle.NonDefaults)) { removeKeys ??= new List <string>(); removeKeys.Add(entry.Key); } } } } if (removeKeys != null) { foreach (var key in removeKeys) { dtoValues.RemoveKey(key); } } if (replaceValues != null) { foreach (var entry in replaceValues) { dtoValues[entry.Key] = entry.Value; } } } if (meta.PopulateAttrs != null) { foreach (var populateAttr in meta.PopulateAttrs) { dtoValues[populateAttr.Field] = appHost.EvalScriptValue(populateAttr, Request); } } var populatorFn = AutoMappingUtils.GetPopulator( typeof(Dictionary <string, object>), meta.DtoType); populatorFn?.Invoke(dtoValues, dto); // Ensure RowVersion is always populated if defined on Request DTO if (meta.RowVersionGetter != null && !dtoValues.ContainsKey(Keywords.RowVersion)) { dtoValues[Keywords.RowVersion] = default(uint); } return(dtoValues); }