Browse Source

Fixes to serialization

Kenric Nugteren 8 tháng trước cách đây
mục cha
commit
39099fde01

+ 64 - 24
InABox.Core/BaseObject.cs

@@ -1,4 +1,5 @@
-using System;
+using Newtonsoft.Json;
+using System;
 using System.Collections;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -49,7 +50,11 @@ namespace InABox.Core
     }
     public class OriginalValues : IOriginalValues
     {
-        private readonly ConcurrentDictionary<string, object?> Dictionary = new ConcurrentDictionary<string, object?>();
+        public OriginalValues()
+        {
+        }
+
+        public ConcurrentDictionary<string, object?> Dictionary { get; set; } = new ConcurrentDictionary<string, object?>();
 
         public object? this[string key] { get => Dictionary[key]; set => Dictionary[key] = value; }
 
@@ -83,7 +88,7 @@ namespace InABox.Core
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
     }
 
-    public interface ILoadedColumns
+    public interface ILoadedColumns : IEnumerable<string>
     {
         public bool Add(string key);
 
@@ -102,6 +107,16 @@ namespace InABox.Core
         {
             return Columns.Contains(key);
         }
+
+        public IEnumerator<string> GetEnumerator()
+        {
+            return Columns.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return Columns.GetEnumerator();
+        }
     }
 
     /// <summary>
@@ -186,9 +201,10 @@ namespace InABox.Core
 
         private bool bChanged;
 
-        [DoNotPersist]
         private IOriginalValues _originalValues;
-        public IOriginalValues OriginalValues
+        [DoNotPersist]
+        [DoNotSerialize]
+        public IOriginalValues OriginalValueList
         {
             get
             {
@@ -197,8 +213,32 @@ namespace InABox.Core
             }
         }
 
+        [DoNotPersist]
+        public ConcurrentDictionary<string, object?>? OriginalValues
+        {
+            get
+            {
+                if(OriginalValueList is OriginalValues v)
+                {
+                    return v.Dictionary;
+                }
+                else
+                {
+                    return null;
+                }
+            }
+            set
+            {
+                if(value != null && OriginalValueList is OriginalValues v)
+                {
+                    v.Dictionary = value;
+                }
+            }
+        }
+
         [DoNotPersist]
         [DoNotSerialize]
+        [JsonIgnore]
         public ILoadedColumns LoadedColumns { get; set; }
 
         protected virtual void SetChanged(string name, object? before, object? after)
@@ -232,7 +272,7 @@ namespace InABox.Core
 
         private bool QueryChanged()
         {
-            if (OriginalValues.Any())
+            if (OriginalValueList.Any())
                 return true;
 
             foreach (var oo in DatabaseSchema.GetSubObjects(this))
@@ -261,8 +301,8 @@ namespace InABox.Core
             if (!BaseObjectExtensions.HasChanged(before, after))
                 return;
 
-            if (!OriginalValues.ContainsKey(name))
-                OriginalValues[name] = before;
+            if (!OriginalValueList.ContainsKey(name))
+                OriginalValueList[name] = before;
             SetChanged(name, before, after);
         }
 
@@ -286,7 +326,7 @@ namespace InABox.Core
             var bObs = IsObserving();
             SetObserving(false);
 
-            foreach (var (key, value) in OriginalValues)
+            foreach (var (key, value) in OriginalValueList)
             {
                 try
                 {
@@ -306,7 +346,7 @@ namespace InABox.Core
                 }
             }
 
-            OriginalValues.Clear();
+            OriginalValueList.Clear();
 
 
             bChanged = false;
@@ -322,7 +362,7 @@ namespace InABox.Core
         {
             bApplyingChanges = true;
 
-            OriginalValues.Clear();
+            OriginalValueList.Clear();
 
             bChanged = false;
 
@@ -338,7 +378,7 @@ namespace InABox.Core
             var type = GetType();
             try
             {
-                foreach (var (key, _) in OriginalValues)
+                foreach (var (key, _) in OriginalValueList)
                     try
                     {
                         if (UserProperties.ContainsKey(key))
@@ -451,7 +491,7 @@ namespace InABox.Core
                 prop.Setter()(Object, value);
                 if(BaseObjectExtensions.HasChanged(oldValue, value))
                 {
-                    Object.OriginalValues[prop.Name] = oldValue;
+                    Object.OriginalValueList[prop.Name] = oldValue;
                 }
             }
             Object.SetObserving(bObs);
@@ -490,13 +530,13 @@ namespace InABox.Core
 
         public static bool HasOriginalValue<T>(this T sender, string propertyname) where T : BaseObject
         {
-            return sender.OriginalValues != null && sender.OriginalValues.ContainsKey(propertyname);
+            return sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(propertyname);
         }
 
         public static TType GetOriginalValue<T, TType>(this T sender, string propertyname) where T : BaseObject
         {
-            return sender.OriginalValues != null && sender.OriginalValues.ContainsKey(propertyname)
-                ? (TType)CoreUtils.ChangeType(sender.OriginalValues[propertyname], typeof(TType))
+            return sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(propertyname)
+                ? (TType)CoreUtils.ChangeType(sender.OriginalValueList[propertyname], typeof(TType))
                 : default;
         }
 
@@ -534,7 +574,7 @@ namespace InABox.Core
                 {
                     var isLocal = !property.HasParentEntityLink()
                         || (property.Parent?.HasParentEntityLink() != true && property.Name.EndsWith(".ID"));
-                    if (isLocal && sender.OriginalValues.TryGetValue(property.Name, out var value))
+                    if (isLocal && sender.OriginalValueList.TryGetValue(property.Name, out var value))
                     {
                         result[property.Name] = value;
                     }
@@ -596,36 +636,36 @@ namespace InABox.Core
         
         public static void SetOriginalValue<T, TType>(this T sender, string propertyname, TType value) where T : BaseObject
         {
-            sender.OriginalValues[propertyname] = value;
+            sender.OriginalValueList[propertyname] = value;
         }
 
         public static bool HasOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property) where T : BaseObject
         {
             //var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
             String propname = CoreUtils.GetFullPropertyName(property, ".");
-            return !String.IsNullOrWhiteSpace(propname) && sender.OriginalValues != null && sender.OriginalValues.ContainsKey(propname);
+            return !String.IsNullOrWhiteSpace(propname) && sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(propname);
         }
 
         public static TType GetOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property) where T : BaseObject
         {
             var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
-            return prop != null && sender.OriginalValues != null && sender.OriginalValues.ContainsKey(prop.Name)
-                ? (TType)CoreUtils.ChangeType(sender.OriginalValues[prop.Name], typeof(TType))
+            return prop != null && sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(prop.Name)
+                ? (TType)CoreUtils.ChangeType(sender.OriginalValueList[prop.Name], typeof(TType))
                 : default;
         }
         
         public static TType GetOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property, TType defaultValue) where T : BaseObject
         {
             var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
-            return prop != null && sender.OriginalValues != null && sender.OriginalValues.ContainsKey(prop.Name)
-                ? (TType)CoreUtils.ChangeType(sender.OriginalValues[prop.Name], typeof(TType))
+            return prop != null && sender.OriginalValueList != null && sender.OriginalValueList.ContainsKey(prop.Name)
+                ? (TType)CoreUtils.ChangeType(sender.OriginalValueList[prop.Name], typeof(TType))
                 : defaultValue;
         }
 
         public static void SetOriginalValue<T, TType>(this T sender, Expression<Func<T, TType>> property, TType value) where T : BaseObject
         {
             var prop = ((MemberExpression)property.Body).Member as PropertyInfo;
-            sender.OriginalValues[prop.Name] = value;
+            sender.OriginalValueList[prop.Name] = value;
         }
     }
 

+ 10 - 0
InABox.Core/CoreTable/CoreTable.cs

@@ -321,6 +321,16 @@ namespace InABox.Core
             }
             return list;
         }
+
+        public BaseObject[] ToArray(Type T)
+        {
+            var arr = new BaseObject[Rows.Count];
+            for(int i = 0; i < Rows.Count; ++i)
+            {
+                arr[i] = Rows[i].ToObject(T);
+            }
+            return arr;
+        }
         public T[] ToArray<T>() where T : BaseObject, new()
         {
             var arr = new T[Rows.Count];

+ 1 - 1
InABox.Core/Imports/BaseImporter.cs

@@ -75,7 +75,7 @@ namespace InABox.Core
             //var prop = CoreUtils.GetProperty(typeof(T), property);
             var type = p2.PropertyType;
 
-            item.OriginalValues[mapping.Property] = CoreUtils.GetPropertyValue(item, mapping.Property);
+            item.OriginalValueList[mapping.Property] = CoreUtils.GetPropertyValue(item, mapping.Property);
 
             if (type == typeof(string))
             {

+ 9 - 2
InABox.Core/LinkedProperties.cs

@@ -27,7 +27,7 @@ namespace InABox.Core
         {
             get
             {
-                _rootDictionary ??= LinkedProperties.GetParent(Object).OriginalValues;
+                _rootDictionary ??= LinkedProperties.GetParent(Object).OriginalValueList;
                 return _rootDictionary;
             }
         }
@@ -85,7 +85,7 @@ namespace InABox.Core
 
         public IEnumerator<KeyValuePair<string, object?>> GetEnumerator()
         {
-            return RootDictionary.Where(x => x.Key.StartsWith(RootPath)).GetEnumerator();
+            return RootDictionary.Where(x => x.Key.StartsWith(RootPath)).Select(x => new KeyValuePair<string, object?>(x.Key[RootPath.Length..], x.Value)).GetEnumerator();
         }
 
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
@@ -140,6 +140,13 @@ namespace InABox.Core
         {
             return RootSet.Contains(ChangeKey(key));
         }
+
+        public IEnumerator<string> GetEnumerator()
+        {
+            return RootSet.Where(x => x.StartsWith(RootPath)).Select(x => x[RootPath.Length..]).GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
     }
 
     public static class LinkedProperties

+ 68 - 2
InABox.Core/Serialization.cs

@@ -48,6 +48,7 @@ namespace InABox.Core
                 _serializerSettings.Converters.Add(new ColumnJsonConverter());
                 _serializerSettings.Converters.Add(new SortOrderJsonConverter());
                 _serializerSettings.Converters.Add(new UserPropertiesJsonConverter());
+                //_serializerSettings.Converters.Add(new BaseObjectJSONConverter());
 
                 _serializerSettings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
             }
@@ -664,7 +665,7 @@ namespace InABox.Core
             where TObject : BaseObject
         {
             var originalValues = new List<Tuple<Type, string, object?>>();
-            foreach (var (key, value) in obj.OriginalValues)
+            foreach (var (key, value) in obj.OriginalValueList)
             {
                 if (DatabaseSchema.Property(obj.GetType(), key) is IProperty prop)
                 {
@@ -696,7 +697,7 @@ namespace InABox.Core
                 if (DatabaseSchema.Property(obj.GetType(), key) is IProperty prop)
                 {
                     var value = reader.ReadBinaryValue(prop.PropertyType);
-                    obj.OriginalValues[prop.Name] = value;
+                    obj.OriginalValueList[prop.Name] = value;
                 }
             }
         }
@@ -862,4 +863,69 @@ namespace InABox.Core
             return objs;
         }
     }
+
+    public class BaseObjectJSONConverter : JsonConverter
+    {
+        public override bool CanConvert(Type objectType)
+        {
+            return objectType.IsSubclassOf(typeof(BaseObject));
+        }
+
+        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+        {
+            var obj = (Activator.CreateInstance(objectType) as BaseObject)!;
+            obj.SetObserving(false);
+
+            if (reader.TokenType == JsonToken.Null)
+                return null;
+
+            var data = JObject.Load(reader);
+
+            foreach(var (k, v) in data)
+            {
+                if (string.Equals(k, "OriginalValues") && v is JObject originalValues)
+                {
+                    foreach(var (origk, origv) in originalValues)
+                    {
+                        if (origv is null) continue;
+
+                        var property = DatabaseSchema.Property(objectType, origk);
+                        if (property is null) continue;
+
+                        obj.OriginalValueList[origk] = origv.ToObject(property.PropertyType);
+                    }
+                }
+                else if(DatabaseSchema.Property(objectType, k) is IProperty prop)
+                {
+                    prop.Setter()(obj, v?.ToObject(prop.PropertyType));
+                }
+            }
+            obj.SetObserving(true);
+            return obj;
+        }
+
+        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+        {
+            if (!(value is BaseObject obj)) return;
+
+            writer.WriteStartObject();
+
+            writer.WritePropertyName("OriginalValues");
+            writer.WriteStartObject();
+            foreach(var (k, v) in obj.OriginalValueList)
+            {
+                writer.WritePropertyName(k);
+                serializer.Serialize(writer, v);
+            }
+            writer.WriteEndObject();
+
+            foreach(var property in DatabaseSchema.Properties(obj.GetType()))
+            {
+                writer.WritePropertyName(property.Name);
+                serializer.Serialize(writer, property.Getter()(obj));
+            }
+
+            writer.WriteEndObject();
+        }
+    }
 }

+ 1 - 1
InABox.Database/DataUpdater.cs

@@ -236,7 +236,7 @@ public static class DataUpdater
 
         var result = DbFactory.NewProvider(Logger.Main).Query(new Filter<GlobalSettings>(x => x.Section).IsEqualTo(nameof(DatabaseVersion)))
             .Rows.FirstOrDefault()?.ToObject<GlobalSettings>() ?? new GlobalSettings() { Section = nameof(DatabaseVersion), Key = "" };
-        result.OriginalValues["Contents"] = result.Contents;
+        result.OriginalValueList["Contents"] = result.Contents;
         result.Contents = Serialization.Serialize(dbVersion);
         DbFactory.NewProvider(Logger.Main).Save(result);
     }