Quellcode durchsuchen

Improvements to DatabaseSchema

Kenric Nugteren vor 1 Jahr
Ursprung
Commit
605036cfc1
2 geänderte Dateien mit 134 neuen und 119 gelöschten Zeilen
  1. 113 107
      InABox.Core/DatabaseSchema/DatabaseSchema.cs
  2. 21 12
      InABox.Core/DatabaseSchema/StandardProperty.cs

+ 113 - 107
InABox.Core/DatabaseSchema/DatabaseSchema.cs

@@ -88,145 +88,145 @@ namespace InABox.Core
                     .Select(x => new SubObject(objectType, x.Item1, x.Item2)));
         }
 
-        private static void RegisterProperties(Type master, Type type, string prefix, StandardProperty? parent)
+        public static void Clear()
+        {
+            _properties = new ConcurrentDictionary<Type, ImmutableDictionary<string, IProperty>>();
+        }
+
+        private static void RegisterProperties(Type master, Type type, string prefix, StandardProperty? parent, Dictionary<string, IProperty> newProperties)
         {
             try
             {
-                var classname = master.EntityName();
                 var properties = CoreUtils.PropertyList(
                     type,
                     x => !x.PropertyType.IsInterface &&
-                        x.GetGetMethod()?.IsPublic == true &&
-                        (x.DeclaringType.IsSubclassOf(typeof(BaseObject)) 
+                        (x.DeclaringType.IsSubclassOf(typeof(BaseObject))
                         || x.DeclaringType.IsSubclassOf(typeof(BaseEditor)))
                 );
-                var classProps = _properties.GetValueOrDefault(master);
 
                 var subObjects = new List<Tuple<Type, string>>();
-                var newProperties = new List<IProperty>();
 
                 foreach (var prop in properties)
                 {
-                    var name = prefix.IsNullOrWhiteSpace() ? prop.Name : $"{prefix}.{prop.Name}";
-                    var p = classProps?.GetValueOrDefault(name);
-                    if (p == null && !prop.GetAccessors(true)[0].IsStatic)
+                    var name = prefix + prop.Name;
+                    if (newProperties.ContainsKey(name)) continue;
+
+                    var getMethod = prop.GetGetMethod();
+                    if (getMethod is null || !getMethod.IsPublic || getMethod.IsStatic) continue;
+
+                    BaseEditor? editor;
+                    if (parent != null && parent.HasEditor && parent.Editor is NullEditor)
+                    {
+                        editor = parent.Editor;
+                    }
+                    else
                     {
-                        BaseEditor? editor;
-                        if (parent != null && parent.HasEditor && parent.Editor is NullEditor)
+                        editor = prop.GetEditor();
+                    }
+
+                    var captionAttr = prop.GetCustomAttribute<Caption>();
+                    var subCaption = captionAttr != null ? captionAttr.Text : prop.Name;
+                    var path = captionAttr == null || captionAttr.IncludePath; // If no caption attribute, we should always include the path
+                    var caption = parent?.Caption ?? ""; // We default to the parent caption if subCaption doesn't exist
+                    if (!string.IsNullOrWhiteSpace(subCaption))
+                    {
+                        if (!string.IsNullOrWhiteSpace(caption) && path)
                         {
-                            editor = parent.Editor;
+                            caption = $"{caption} {subCaption}";
                         }
                         else
                         {
-                            editor = prop.GetEditor();
-                        }
-
-                        var captionAttr = prop.GetCustomAttribute<Caption>();
-                        var subCaption = captionAttr != null ? captionAttr.Text : prop.Name;
-                        var path = captionAttr == null || captionAttr.IncludePath; // If no caption attribute, we should always include the path
-                        var caption = parent?.Caption ?? ""; // We default to the parent caption if subCaption doesn't exist
-                        if (!string.IsNullOrWhiteSpace(subCaption))
-                        {
-                            if (!string.IsNullOrWhiteSpace(caption) && path)
-                            {
-                                caption = $"{caption} {subCaption}";
-                            }
-                            else
-                            {
-                                caption = subCaption;
-                            }
+                            caption = subCaption;
                         }
+                    }
 
-                        // Once the parent page has been found, this property is cemented to that page - it cannot change page to its parent
-                        // The same goes for sequence
-                        var page = parent?.Page;
-                        var sequence = parent?.Sequence;
-                        if (string.IsNullOrWhiteSpace(page))
+                    // Once the parent page has been found, this property is cemented to that page - it cannot change page to its parent
+                    // The same goes for sequence
+                    var page = parent?.Page;
+                    var sequence = parent?.Sequence;
+                    if (string.IsNullOrWhiteSpace(page))
+                    {
+                        var sequenceAttribute = prop.GetCustomAttribute<EditorSequence>();
+                        if (sequenceAttribute != null)
                         {
-                            var sequenceAttribute = prop.GetCustomAttribute<EditorSequence>();
-                            if (sequenceAttribute != null)
-                            {
-                                page = sequenceAttribute.Page;
-                                sequence = sequenceAttribute.Sequence;
-                            }
+                            page = sequenceAttribute.Page;
+                            sequence = sequenceAttribute.Sequence;
                         }
-                        editor = editor?.Clone() as BaseEditor;
-                        if (editor != null)
-                        {
-                            editor.Page = page;
-                            editor.Caption = caption;
-                            editor.EditorSequence = (int)(sequence ?? 999);
+                    }
+                    editor = editor?.Clone() as BaseEditor;
+                    if (editor != null)
+                    {
+                        editor.Page = page;
+                        editor.Caption = caption;
+                        editor.EditorSequence = (int)(sequence ?? 999);
 
-                            editor.Security = prop.GetCustomAttributes<SecurityAttribute>().ToArray();
-                        }
+                        editor.Security = prop.GetCustomAttributes<SecurityAttribute>().ToArray();
+                    }
 
-                        bool required = false;
-                        if (parent == null || parent.Required)
-                        {
-                            required = prop.GetCustomAttribute<RequiredColumnAttribute>() != null;
-                        }
+                    bool required = false;
+                    if (parent == null || parent.Required)
+                    {
+                        required = prop.GetCustomAttribute<RequiredColumnAttribute>() != null;
+                    }
 
-                        LoggablePropertyAttribute? loggable = null;
-                        if (parent == null || parent.Loggable != null)
-                        {
-                            loggable = prop.GetCustomAttribute<LoggablePropertyAttribute>();
-                        }
+                    LoggablePropertyAttribute? loggable = null;
+                    if (parent == null || parent.Loggable != null)
+                    {
+                        loggable = prop.GetCustomAttribute<LoggablePropertyAttribute>();
+                    }
 
-                        var newProperty = new StandardProperty
-                        {
-                            _class = master,
-                            //Class = classname,
-                            Name = name,
-                            PropertyType = prop.PropertyType,
-                            Editor = editor ?? new NullEditor(),
-                            HasEditor = editor != null,
-                            Caption = caption,
-                            Sequence = sequence ?? 999,
-                            Page = page ?? "",
-                            Required = required,
-                            Loggable = loggable,
-                            Parent = parent,
-                            Property = prop
-                        };
-
-                        var parentWithEditable = newProperty.GetOuterParent(x =>
-                            x is StandardProperty st
-                            && st.Property.GetCustomAttribute<EditableAttribute>() != null);
-                        if(parentWithEditable != null)
-                        {
-                            var attr = (parentWithEditable as StandardProperty)!.Property.GetCustomAttribute<EditableAttribute>()!;
-                            newProperty.Editor.Editable = newProperty.Editor.Editable.Combine(attr.Editable);
-                        }
-                        else if(prop.GetCustomAttribute<EditableAttribute>() is EditableAttribute attr)
-                        {
-                            newProperty.Editor.Editable = newProperty.Editor.Editable.Combine(attr.Editable);
-                        }
+                    var newProperty = new StandardProperty
+                    {
+                        _class = master,
+                        Name = name,
+                        PropertyType = prop.PropertyType,
+                        Editor = editor ?? new NullEditor(),
+                        HasEditor = editor != null,
+                        Caption = caption,
+                        Sequence = sequence ?? 999,
+                        Page = page ?? "",
+                        Required = required,
+                        Loggable = loggable,
+                        Parent = parent,
+                        Property = prop
+                    };
+
+                    var parentWithEditable = newProperty.GetOuterParent(x =>
+                        x is StandardProperty st
+                        && st.Property.GetCustomAttribute<EditableAttribute>() != null);
+                    if(parentWithEditable != null)
+                    {
+                        var attr = (parentWithEditable as StandardProperty)!.Property.GetCustomAttribute<EditableAttribute>()!;
+                        newProperty.Editor.Editable = newProperty.Editor.Editable.Combine(attr.Editable);
+                    }
+                    else if(prop.GetCustomAttribute<EditableAttribute>() is EditableAttribute attr)
+                    {
+                        newProperty.Editor.Editable = newProperty.Editor.Editable.Combine(attr.Editable);
+                    }
 
-                        var isLink = typeof(IEntityLink).IsAssignableFrom(prop.PropertyType);
-                        var isEnclosedEntity = typeof(IEnclosedEntity).IsAssignableFrom(prop.PropertyType);
-                        var isBaseEditor = prop.PropertyType.Equals(typeof(BaseEditor)) ||
-                            prop.PropertyType.IsSubclassOf(typeof(BaseEditor));
-                        if ((isLink || isEnclosedEntity) && !isBaseEditor)
-                        {
-                            subObjects.Add(new Tuple<Type, string>(prop.PropertyType, prop.Name));
-                        }
+                    var isLink = prop.PropertyType.HasInterface<IEntityLink>();
+                    var isEnclosedEntity = prop.PropertyType.HasInterface<IEnclosedEntity>();
+                    var isBaseEditor = prop.PropertyType.HasInterface<IBaseEditor>();
+                    if ((isLink || isEnclosedEntity) && !isBaseEditor)
+                    {
+                        subObjects.Add(new Tuple<Type, string>(prop.PropertyType, prop.Name));
+                    }
 
-                        if (isLink || isEnclosedEntity || isBaseEditor)
-                        {
-                            RegisterProperties(master, prop.PropertyType, name, newProperty);
-                        }
-                        else
-                        {
-                            newProperties.Add(newProperty);
-                        }
+                    if (isLink || isEnclosedEntity || isBaseEditor)
+                    {
+                        RegisterProperties(master, prop.PropertyType, name + ".", newProperty, newProperties);
+                    }
+                    else
+                    {
+                        newProperties.Add(newProperty.Name, newProperty);
                     }
                 }
 
-                RegisterProperties(master, newProperties);
                 RegisterSubObjects(type, subObjects);
 
-                if (type.IsSubclassOf(typeof(BaseObject)))
-                    RegisterProperties(master, type.BaseType, prefix, parent);
+                // I don't actually think we need this, since PropertyList gives us properties of our parent.
+                //if (type.IsSubclassOf(typeof(BaseObject)) && type.BaseType != typeof(BaseObject))
+                //    RegisterProperties(master, type.BaseType, prefix, parent, newProperties);
             }
             catch (Exception e)
             {
@@ -236,7 +236,12 @@ namespace InABox.Core
 
         private static void RegisterProperties(Type type)
         {
-            RegisterProperties(type, type, "", null);
+            var properties = new Dictionary<string, IProperty>();
+            RegisterProperties(type, type, "", null, properties);
+            if(properties.Count > 0)
+            {
+                RegisterProperties(type, properties.Values);
+            }
         }
 
         public static object? DefaultValue(Type type)
@@ -318,6 +323,7 @@ namespace InABox.Core
         {
             return CheckProperties(type)?.Select(x => x.Value) ?? Enumerable.Empty<IProperty>();
         }
+        public static IEnumerable<IProperty> Properties<T>() => Properties(typeof(T));
         
         public static IProperty? Property(Type type, string name)
         {

+ 21 - 12
InABox.Core/DatabaseSchema/StandardProperty.cs

@@ -17,6 +17,8 @@ namespace InABox.Core
 
         private Action<object, object?> _setter;
 
+        private bool _checkedExpressions;
+
         public string _type = "";
         public Type _propertyType = typeof(object);
 
@@ -33,7 +35,7 @@ namespace InABox.Core
             set
             {
                 _class = CoreUtils.GetEntity(value);
-                CheckExpressions();
+                ClearExpressions();
             }
         }
 
@@ -52,7 +54,7 @@ namespace InABox.Core
             set
             {
                 _name = value;
-                CheckExpressions();
+                ClearExpressions();
             }
         }
 
@@ -82,8 +84,8 @@ namespace InABox.Core
             {
                 _propertyType = value;
                 _type = value.EntityName();
-                IsEntityLink = _propertyType.GetInterfaces().Contains(typeof(IEntityLink));
-                IsEnclosedEntity = _propertyType.GetInterfaces().Contains(typeof(IEnclosedEntity));
+                IsEntityLink = _propertyType.HasInterface(typeof(IEntityLink));
+                IsEnclosedEntity = _propertyType.HasInterface(typeof(IEnclosedEntity));
                 IsParent = IsEnclosedEntity || IsEntityLink;
             }
         }
@@ -161,11 +163,15 @@ namespace InABox.Core
 
         public Func<object, object> Getter()
         {
+            if (_getter is null) CheckExpressions();
+
             return _getter;
         }
 
         public Action<object, object?> Setter()
         {
+            if (_setter is null) CheckExpressions();
+
             return _setter;
         }
 
@@ -190,20 +196,21 @@ namespace InABox.Core
             return string.Format("{0}.{1}", Class, Name);
         }
 
+        private void ClearExpressions()
+        {
+            _checkedExpressions = false;
+            _getter = null;
+            _setter = null;
+        }
+
         private void CheckExpressions()
         {
+            if(_checkedExpressions) return;
+
             if (_class == null)
                 return;
             if (string.IsNullOrEmpty(_name))
                 return;
-            try
-            {
-                _propertyType = CoreUtils.GetProperty(_class, _name).PropertyType;
-            }
-            catch (Exception e)
-            {
-                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-            }
 
             try
             {
@@ -222,6 +229,8 @@ namespace InABox.Core
             {
                 Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
             }
+
+            _checkedExpressions = true;
         }
 
         private class StandardPropertyClassLookups : LookupGenerator<object>