private static void EnsureAllAssociationsHaveIds(StorageContext context, object storageSetValue, Type modelType, List <PropertyInfo> storageSets, IReadOnlyDictionary <string, Metadata> metadataMap) { var storageSetType = StorageManagerUtil.GenericStorageSetType.MakeGenericType(modelType); var method = storageSetType.GetMethod(StorageManagerUtil.GetEnumerator); var enumerator = (IEnumerator)method.Invoke(storageSetValue, new object[] { }); while (enumerator.MoveNext()) { var model = enumerator.Current; foreach (var prop in model.GetType().GetProperties()) { if (prop.GetValue(model) == null || !StorageManagerUtil.IsInContext(storageSets, prop) && !StorageManagerUtil.IsListInContext(storageSets, prop)) { continue; } if (StorageManagerUtil.IsInContext(storageSets, prop)) { EnsureOneAssociationHasId(context, prop.GetValue(model), prop.PropertyType, storageSets, metadataMap); } if (StorageManagerUtil.IsListInContext(storageSets, prop)) { EnsureManyAssociationHasId(context, prop.GetValue(model), prop, storageSets, metadataMap); } } } }
private static object CreateContext(Type contextType, IReadOnlyDictionary <Type, Dictionary <int, SerializedModel> > stringModels) { var context = Activator.CreateInstance(contextType); foreach (var prop in contextType.GetProperties()) { if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(StorageSet <>)) { var modelType = prop.PropertyType.GetGenericArguments()[0]; var storageSetType = StorageManagerUtil.GenericStorageSetType.MakeGenericType(modelType); var storageTableName = Util.GetStorageTableName(contextType, modelType); var metadata = StorageManagerUtil.LoadMetadata(storageTableName); if (stringModels.ContainsKey(modelType)) { var map = stringModels[modelType]; Logger.LoadModelInContext(modelType, map.Count); } else { Logger.LoadModelInContext(modelType, 0); } var storageSet = metadata != null ? LoadStorageSet(storageSetType, contextType, modelType, stringModels[modelType]) : CreateNewStorageSet(storageSetType, contextType); prop.SetValue(context, storageSet); } } return(context); }
private static Dictionary <Type, Dictionary <int, SerializedModel> > LoadStringModels(Type contextType, IEnumerable <PropertyInfo> storageSets) { var stringModels = new Dictionary <Type, Dictionary <int, SerializedModel> >(); foreach (var prop in storageSets) { var modelType = prop.PropertyType.GetGenericArguments()[0]; var map = new Dictionary <int, SerializedModel>(); var storageTableName = Util.GetStorageTableName(contextType, modelType); var metadata = StorageManagerUtil.LoadMetadata(storageTableName); if (metadata == null) { continue; } foreach (var guid in metadata.Guids) { var name = $"{storageTableName}-{guid}"; var serializedModel = BlazorDBInterop.GetItem(name, false); var id = FindIdInSerializedModel(serializedModel); map.Add(id, new SerializedModel { StringModel = serializedModel }); } stringModels.Add(modelType, map); } return(stringModels); }
private string FixAssociationsInStringModels(SerializedModel stringModel, Type modelType, List <PropertyInfo> storageSets, Dictionary <Type, Dictionary <int, SerializedModel> > stringModels) { var result = stringModel.StringModel; foreach (var prop in modelType.GetProperties()) { if (StorageManagerUtil.IsInContext(storageSets, prop)) { if (TryGetIdFromSerializedModel(result, prop.Name, out var id)) { var updated = GetAssociatedStringModel(stringModels, prop.PropertyType, id); result = ReplaceIdWithAssociation(result, prop.Name, id, updated); } } if (StorageManagerUtil.IsListInContext(storageSets, prop)) { if (TryGetIdListFromSerializedModel(result, prop.Name, out var idList)) { var sb = new StringBuilder(); foreach (var id in idList) { var updated = GetAssociatedStringModel(stringModels, prop.PropertyType.GetGenericArguments()[0], id); sb.Append(updated).Append(","); } var strList = sb.ToString().Substring(0, sb.ToString().Length - 1); result = ReplaceListWithAssociationList(result, prop.Name, strList); } } } return(result); }
public async Task <int> SaveContextToLocalStorage(StorageContext context) { var total = 0; var contextType = context.GetType(); await Logger.ContextSaved(contextType); var storageSets = StorageManagerUtil.GetStorageSets(contextType); var error = ValidateModels(context, storageSets); if (error == null) { var metadataMap = await LoadMetadataList(context, storageSets, contextType); total = await SaveStorageSets(context, total, contextType, storageSets, metadataMap); Logger.EndGroup(); } else { await BlazorLogger.Logger.Error("SaveChanges() terminated due to validation error"); Logger.EndGroup(); throw new BlazorDBUpdateException(error); } return(total); }
private string ScanModelForAssociations(object model, List <PropertyInfo> storageSets, string serializedModel) { var result = serializedModel; foreach (var prop in model.GetType().GetProperties()) { if (prop.GetValue(model) != null && StorageManagerUtil.IsInContext(storageSets, prop)) { var associatedModel = prop.GetValue(model); var idProp = associatedModel.GetType().GetProperty(StorageManagerUtil.ID); //TODO: Handle missing Id prop var id = Convert.ToString(idProp.GetValue(associatedModel)); var serializedItem = JsonUtil.Serialize(model); result = ReplaceModelWithId(result, serializedItem, id); } if (prop.GetValue(model) != null && StorageManagerUtil.IsListInContext(storageSets, prop)) { var modelList = (IEnumerable)prop.GetValue(model); foreach (var item in modelList) { var idProp = item.GetType().GetProperty(StorageManagerUtil.ID); //TODO: Handle missing Id prop var id = Convert.ToString(idProp.GetValue(item)); var serializedItem = JsonUtil.Serialize(item); result = ReplaceModelWithId(result, serializedItem, id); } } } return(result); }
private static string ReplaceIdWithAssociation(string result, string name, int id, string stringModel) { var stringToFind = $"\"{name}\":{id}"; var nameIndex = result.IndexOf(stringToFind, StringComparison.Ordinal); var index = result.IndexOf(id.ToString(), nameIndex, StringComparison.Ordinal); result = StorageManagerUtil.ReplaceString(result, index, index + id.ToString().Length, stringModel); return(result); }
private static string ReplaceListWithAssociationList(string serializedModel, string propName, string strList) { var propStart = serializedModel.IndexOf($"\"{propName}\":[", StringComparison.Ordinal); var start = serializedModel.IndexOf('[', propStart) + 1; var end = serializedModel.IndexOf(']', start); var result = StorageManagerUtil.ReplaceString(serializedModel, start, end, strList); return(result); }
private static Dictionary <Type, Dictionary <int, SerializedModel> > DeserializeModels( Dictionary <Type, Dictionary <int, SerializedModel> > stringModels, List <PropertyInfo> storageSets) { foreach (var map in stringModels) { var modelType = map.Key; foreach (var sm in map.Value) { var stringModel = sm.Value; if (!stringModel.HasAssociation) { stringModel.Model = DeserializeModel(modelType, stringModel.StringModel); } } } foreach (var map in stringModels) //TODO: Fix associations that are more than one level deep { var modelType = map.Key; foreach (var sm in map.Value) { var stringModel = sm.Value; if (stringModel.Model != null) { continue; } var model = DeserializeModel(modelType, stringModel.StringModel); foreach (var prop in model.GetType().GetProperties()) { if (StorageManagerUtil.IsInContext(storageSets, prop) && prop.GetValue(model) != null) { var associatedLocalModel = prop.GetValue(model); var localIdProp = associatedLocalModel.GetType() .GetProperty(StorageManagerUtil.Id); if (localIdProp == null) { throw new ArgumentException("Model must have Id property"); } var localId = Convert.ToInt32(localIdProp.GetValue(associatedLocalModel)); var associatdRemoteModel = GetModelFromStringModels(stringModels, associatedLocalModel.GetType(), localId) .Model; prop.SetValue(model, associatdRemoteModel); } } stringModel.Model = model; } } return(stringModels); }
public int SaveContextToLocalStorage(StorageContext context) { int total = 0; var contextType = context.GetType(); Logger.ContextSaved(contextType); var storageSets = StorageManagerUtil.GetStorageSets(contextType); total = SaveStorageSets(context, total, contextType, storageSets); Logger.EndGroup(); return(total); }
private bool HasListAssociation(List <PropertyInfo> storageSets, Type modelType, SerializedModel stringModel) { var found = false; foreach (var prop in modelType.GetProperties()) { if (StorageManagerUtil.IsListInContext(storageSets, prop)) { found = true; break; } } return(found); }
public void LoadContextFromStorageOrCreateNew(IServiceCollection serviceCollection, Type contextType) { Logger.StartContextType(contextType); var storageSets = StorageManagerUtil.GetStorageSets(contextType); var stringModels = LoadStringModels(contextType, storageSets); //PrintStringModels(stringModels); stringModels = ScanNonAssociationModels(storageSets, stringModels); stringModels = ScanAssociationModels(storageSets, stringModels); stringModels = DeserializeModels(stringModels, storageSets); //PrintStringModels(stringModels); var context = CreateContext(contextType, stringModels); RegisterContext(serviceCollection, contextType, context); Logger.EndGroup(); }
public async Task LoadContextFromLocalStorage(StorageContext context) { var contextType = context.GetType(); await Logger.StartContextType(contextType); var storageSets = StorageManagerUtil.GetStorageSets(contextType); var stringModels = await LoadStringModels(contextType, storageSets); //PrintStringModels(stringModels); stringModels = ScanNonAssociationModels(storageSets, stringModels); stringModels = ScanAssociationModels(storageSets, stringModels); stringModels = DeserializeModels(stringModels, storageSets); //PrintStringModels(stringModels); await EnrichContext(context, contextType, stringModels); Logger.EndGroup(); }
private int SaveStorageSets(StorageContext context, int total, Type contextType, List <PropertyInfo> storageSets) { foreach (var prop in storageSets) { var storageSetValue = prop.GetValue(context); var modelType = prop.PropertyType.GetGenericArguments()[0]; var storageTableName = Util.GetStorageTableName(contextType, modelType); var guids = SaveModels(storageSetValue, modelType, storageTableName, storageSets); total += guids.Count; var oldMetadata = StorageManagerUtil.LoadMetadata(storageTableName); SaveMetadata(storageTableName, guids, contextType, modelType); if (oldMetadata != null) { DeleteOldModelsFromStorage(oldMetadata, storageTableName); } Logger.StorageSetSaved(modelType, guids.Count); } return(total); }
private static IReadOnlyDictionary <string, Metadata> LoadMetadataList(StorageContext context, IEnumerable <PropertyInfo> storageSets, Type contextType) { var map = new Dictionary <string, Metadata>(); foreach (var prop in storageSets) { var modelType = prop.PropertyType.GetGenericArguments()[0]; var storageTableName = Util.GetStorageTableName(contextType, modelType); var metadata = StorageManagerUtil.LoadMetadata(storageTableName) ?? new Metadata { Guids = new List <Guid>(), ContextName = Util.GetFullyQualifiedTypeName(context.GetType()), ModelName = Util.GetFullyQualifiedTypeName(modelType) }; map.Add(Util.GetFullyQualifiedTypeName(modelType), metadata); } return(map); }
private static string ScanModelForAssociations(object model, List <PropertyInfo> storageSets, string serializedModel) { var result = serializedModel; foreach (var prop in model.GetType().GetProperties()) { if (prop.GetValue(model) == null || !StorageManagerUtil.IsInContext(storageSets, prop) && !StorageManagerUtil.IsListInContext(storageSets, prop)) { continue; } if (StorageManagerUtil.IsInContext(storageSets, prop)) { result = FixOneAssociation(model, prop, result); } if (StorageManagerUtil.IsListInContext(storageSets, prop)) { result = FixManyAssociation(model, prop, result); } } return(result); }
private static bool HasListAssociation(List <PropertyInfo> storageSets, Type modelType) { return(modelType.GetProperties().Any(prop => StorageManagerUtil.IsListInContext(storageSets, prop))); }