Prechádzať zdrojové kódy

Wrote the code for new system, now need to update all the links.

Kenric Nugteren 1 rok pred
rodič
commit
7e72c505c1

+ 3 - 0
InABox.Core/BaseObject.cs

@@ -32,6 +32,9 @@ namespace InABox.Core
         public BaseObject()
         {
             SetObserving(false);
+
+            DatabaseSchema.InitializeEntityLinks(this);
+
             Init();
             SetObserving(true);
         }

+ 12 - 0
InABox.Core/DatabaseSchema/CustomProperty.cs

@@ -78,6 +78,18 @@ namespace InABox.Core
             }
         }
 
+        [DoNotPersist]
+        [DoNotSerialize]
+        public Type? ClassType
+        {
+            get => _class;
+            set
+            {
+                _class = value;
+                CheckExpressions();
+            }
+        }
+
         [EditorSequence(2)]
         public string Name
         {

+ 53 - 8
InABox.Core/DatabaseSchema/DatabaseSchema.cs

@@ -9,9 +9,27 @@ namespace InABox.Core
     public static class DatabaseSchema
     {
         // {className: {propertyName: property}}
-        private static Dictionary<string, Dictionary<string, IProperty>> _Properties { get; }
+        private static Dictionary<string, Dictionary<string, IProperty>> _properties { get; }
             = new Dictionary<string, Dictionary<string, IProperty>>();
 
+        private static Dictionary<Type, List<IProperty>> _entityLinks { get; } = new Dictionary<Type, List<IProperty>>();
+
+        private static List<IProperty> GetEntityLinks(Type t)
+        {
+            return _entityLinks.GetValueOrDefault(t) ?? new List<IProperty>();
+        }
+
+        public static void InitializeEntityLinks(BaseObject obj)
+        {
+            foreach(var linkProp in GetEntityLinks(obj.GetType()))
+            {
+                var link = (Activator.CreateInstance(linkProp.PropertyType) as IEntityLink)!;
+                linkProp.Setter()(obj, link);
+                link.SetLinkedParent(obj);
+                link.SetLinkedPath(linkProp.Name);
+            }
+        }
+
         /*private static BaseEditor GetPropertyEditor(Type type, PropertyInfo property, string propertyName)
         {
             BaseEditor editor = new NullEditor();
@@ -60,6 +78,23 @@ namespace InABox.Core
             return editor;
         }*/
 
+        private static void RegisterEntityLink(IProperty property)
+        {
+            lock (_updatelock)
+            {
+                var type = property.Parent?.PropertyType ?? property.ClassType;
+                if(type != null)
+                {
+                    if (!_entityLinks.TryGetValue(type, out var properties))
+                    {
+                        properties = new List<IProperty>();
+                        _entityLinks[type] = properties;
+                    }
+                    properties.Add(property);
+                }
+            }
+        }
+
         private static void RegisterProperties(Type master, Type type, string prefix, StandardProperty? parent)
         {
             try
@@ -72,7 +107,7 @@ namespace InABox.Core
                         (x.DeclaringType.IsSubclassOf(typeof(BaseObject)) 
                         || x.DeclaringType.IsSubclassOf(typeof(BaseEditor)))
                 ); //.OrderBy(x=>x.Name);
-                var classProps = _Properties.GetValueOrDefault(classname);
+                var classProps = _properties.GetValueOrDefault(classname);
 
                 foreach (var prop in properties)
                 {
@@ -159,6 +194,10 @@ namespace InABox.Core
                                 Parent = parent,
                                 Property = prop
                             };
+                            if (newProperty.IsEntityLink)
+                            {
+                                RegisterEntityLink(newProperty);
+                            }
 
                             if (prop.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) ||
                                 prop.PropertyType.GetInterfaces().Contains(typeof(IEnclosedEntity)) ||
@@ -209,12 +248,18 @@ namespace InABox.Core
         {
             lock (_updatelock)
             {
-                if (!_Properties.ContainsKey(entry.Class))
-                    _Properties[entry.Class] = new Dictionary<string, IProperty>();
-                _Properties[entry.Class][entry.Name] = entry;
+                if (!_properties.ContainsKey(entry.Class))
+                    _properties[entry.Class] = new Dictionary<string, IProperty>();
+                _properties[entry.Class][entry.Name] = entry;
+
                 //var dict = _Properties.GetOrAdd(entry.Class, className => new Dictionary<string, IProperty>());
                 //dict.TryAdd(entry.Name, entry);
             }
+
+            if (entry.IsEntityLink)
+            {
+                RegisterEntityLink(entry);
+            }
         }
 
         public static void Load(CustomProperty[] customproperties)
@@ -226,7 +271,7 @@ namespace InABox.Core
         private static void CheckProperties(Type type)
         {
             var entityName = type.EntityName();
-            var props = _Properties.GetValueOrDefault(entityName);
+            var props = _properties.GetValueOrDefault(entityName);
             var hasprops = props?.Any(x => x.Value is StandardProperty) == true;
             if (type.IsSubclassOf(typeof(BaseObject)) && !hasprops)
                 RegisterProperties(type);
@@ -236,7 +281,7 @@ namespace InABox.Core
         {
             CheckProperties(type);
             var entityName = type.EntityName();
-            return _Properties.GetValueOrDefault(entityName)?.Select(x => x.Value) ?? Array.Empty<IProperty>();
+            return _properties.GetValueOrDefault(entityName)?.Select(x => x.Value) ?? Array.Empty<IProperty>();
         }
         
         public static IProperty? Property(Type type, string name)
@@ -245,7 +290,7 @@ namespace InABox.Core
             var entityName = type.EntityName();
 
             //IProperty prop = _Properties.ToArray().FirstOrDefault(x => (x.Class.Equals(type.EntityName())) && (x.Name.Equals(name)));
-            var prop = _Properties.GetValueOrDefault(entityName)?.GetValueOrDefault(name);
+            var prop = _properties.GetValueOrDefault(entityName)?.GetValueOrDefault(name);
 
             // Walk up the inheritance tree, see if an ancestor has this property
             if (prop == null && type.BaseType != null)

+ 2 - 0
InABox.Core/DatabaseSchema/IProperty.cs

@@ -8,6 +8,8 @@ namespace InABox.Core
     {
         string Class { get; set; }
 
+        Type? ClassType { get; set; }
+
         string Name { get; set; }
 
         string Type { get; set; }

+ 9 - 0
InABox.Core/DatabaseSchema/StandardProperty.cs

@@ -37,6 +37,15 @@ namespace InABox.Core
             }
         }
 
+        public Type? ClassType
+        {
+            get => _class;
+            set
+            {
+                _class = value ?? typeof(object);
+            }
+        }
+
         public string Name
         {
             get => _name;

+ 46 - 17
InABox.Core/EntityLink.cs

@@ -1,4 +1,5 @@
-using System;
+using Expressive;
+using System;
 using System.Dynamic;
 using System.Linq;
 
@@ -13,6 +14,14 @@ namespace InABox.Core
         bool Synchronise(object entity);
         bool Clear();
         bool IsValid();
+
+        BaseObject GetLinkedParent();
+
+        void SetLinkedParent(BaseObject obj);
+
+        string GetLinkedPath();
+
+        void SetLinkedPath(string path);
     }
 
     public interface IEntityLink<T> : IEntityLink
@@ -21,21 +30,40 @@ namespace InABox.Core
 
     public abstract class EntityLink<T> : BaseObject, IEntityLink<T> where T : BaseObject, new()
     {
-
+        /*
         private Func<BaseObject>? _linkedentity;
         
         [DoNotSerialize]
-        protected BaseObject? LinkedEntity() => _linkedentity?.Invoke();
+        protected BaseObject? LinkedEntity() => _linkedentity?.Invoke();*/
+
+        private BaseObject _linkedParent;
+
+        private string _linkedPath;
+
+        public void SetLinkedParent(BaseObject parent)
+        {
+            _linkedParent = parent;
+        }
+
+        public void SetLinkedPath(string path)
+        {
+            _linkedPath = path;
+        }
+
+        public BaseObject GetLinkedParent() => _linkedParent;
 
-        //[Obsolete("Please supply linked Entity")]
+        public string GetLinkedPath() => _linkedPath;
+
+        /*
+        [Obsolete("Please supply linked Entity")]
         public EntityLink()
         {
         }
 
-        public EntityLink(Func<BaseObject>? entity) 
+        public EntityLink(Func<BaseObject>? entity, string name) 
         {
             _linkedentity = entity;
-        }
+        }*/
 
         [NullEditor]
         public abstract Guid ID { get; set; }
@@ -83,13 +111,11 @@ namespace InABox.Core
                 }
             }
 
-            var le = LinkedEntity();
-            if (le != null)
-                foreach (var link in LinkedProperties.Find(le,this))
-                {
-                    link.Update(this, le);
-                    result = true;
-                }
+            foreach (var link in LinkedProperties.Find(this, out var parent))
+            {
+                link.Update(this, parent);
+                result = true;
+            }
 
             return result;
         }
@@ -118,12 +144,15 @@ namespace InABox.Core
 
         protected override void DoPropertyChanged(string name, object? before, object? after)
         {
-            var le = LinkedEntity();
-            if (IsObserving() && le != null)
+            if (IsObserving())
             {
-                var link = LinkedProperties.Find(le, this).FirstOrDefault(x => x.Source.Equals(name));
+                if(LinkedProperties.Find(this, name, out var link, out var parent))
+                {
+                    link.Update(this, parent);
+                }
+                /*var link = LinkedProperties.Find(le, this).FirstOrDefault(x => x.Source.Equals(name));
                 if (link != null)
-                    link.Update(this, le);
+                    link.Update(this, le);*/
             }
         }
 

+ 71 - 5
InABox.Core/LinkedProperties.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Linq.Expressions;
 
@@ -8,16 +9,21 @@ namespace InABox.Core
     public static class LinkedProperties
     {
 
-        private static readonly List<ILinkedProperty> _LinkedProperties = new List<ILinkedProperty>();
-
-        public static IEnumerable<ILinkedProperty> All => _LinkedProperties;
+        private static readonly Dictionary<Type, List<ILinkedProperty>> _LinkedProperties = new Dictionary<Type, List<ILinkedProperty>>();
         
         public static void Register<TLinkedEntity, TEntityLink, TType>(Expression<Func<TLinkedEntity,TEntityLink>> path, Expression<Func<TEntityLink, TType>> source,
             Expression<Func<TLinkedEntity, TType>> target)
         {
             var map = new LinkedProperty<TLinkedEntity, TEntityLink, TType>(path, source, target);
-            if (!_LinkedProperties.Any(x => x.Equals(map)))
-                _LinkedProperties.Add(map);
+            if(!_LinkedProperties.TryGetValue(map.Type, out var props))
+            {
+                props = new List<ILinkedProperty>();
+                _LinkedProperties[map.Type] = props;
+            }
+            if(!props.Any(x => x.Equals(map)))
+            {
+                props.Add(map);
+            }
         }
 
         public static IEnumerable<ILinkedProperty> Find(object parent, object path)
@@ -26,6 +32,66 @@ namespace InABox.Core
             var filtered =  all.Where(x => CoreUtils.GetPropertyValue(parent,x.Path)?.GetType() == path?.GetType());
             return filtered;
         }
+
+        private static BaseObject GetParent(IEntityLink link)
+        {
+            while (true)
+            {
+                var parent = link.GetLinkedParent();
+                if(parent is IEntityLink parentLink)
+                {
+                    link = parentLink;
+                }
+                else
+                {
+                    return parent;
+                }
+            }
+        }
+
+        private static string GetPath(IEntityLink link)
+        {
+            var path = link.GetLinkedPath();
+            while (true)
+            {
+                var parent = link.GetLinkedParent();
+                if (parent is IEntityLink parentLink)
+                {
+                    link = parentLink;
+                    path = $"{link.GetLinkedPath()}.{path}";
+                }
+                else
+                {
+                    return path;
+                }
+            }
+        }
+
+        public static IEnumerable<ILinkedProperty> Find(IEntityLink link, out BaseObject parent)
+        {
+            parent = GetParent(link);
+            if (!_LinkedProperties.TryGetValue(parent.GetType(), out var props))
+            {
+                return Enumerable.Empty<ILinkedProperty>();
+            }
+
+            var path = GetPath(link);
+            return  props.Where(x => x.Path == path);
+        }
+
+        public static bool Find(IEntityLink link, string name, [NotNullWhen(true)] out ILinkedProperty? property, out BaseObject parent)
+        {
+            parent = GetParent(link);
+            if(!_LinkedProperties.TryGetValue(parent.GetType(), out var props))
+            {
+                property = null;
+                return false;
+            }
+
+            var path = GetPath(link);
+            property = props.FirstOrDefault(x => x.Path == path && x.Source == name);
+            return property != null;
+        }
         
     }
 }