瀏覽代碼

Improvements to AutoEntityUnionGenerator

Frank van den Bos 2 年之前
父節點
當前提交
3980ca00ae
共有 2 個文件被更改,包括 97 次插入29 次删除
  1. 57 10
      InABox.Core/AutoEntity/AutoEntityUnionGenerator.cs
  2. 40 19
      inabox.database.sqlite/SQLiteProvider.cs

+ 57 - 10
InABox.Core/AutoEntity/AutoEntityUnionGenerator.cs

@@ -1,14 +1,61 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Linq.Expressions;
 
 namespace InABox.Core
 {
     
     public interface IAutoEntityUnionGenerator : IAutoEntityGenerator
     {
-        Type[] Entities { get; }
-        IFilter? Filter(Type type);
+        IAutoEntityUnionTable[] Tables { get; }
+    }
+
+    public interface IAutoEntityUnionConstant
+    {
+        object Value { get; }
+        IColumn Mapping { get; }
+    }
+
+    public class AutoEntityUnionConstant : IAutoEntityUnionConstant
+    {
+        public object Value { get; private set; }
+        public IColumn Mapping { get; private set; }
+
+        public AutoEntityUnionConstant(object value, IColumn mapping)
+        {
+            Value = value;
+            Mapping = mapping;
+        }
+    }
+    
+    public interface IAutoEntityUnionTable
+    {
+        Type Entity { get; }
+        IFilter Filter { get; }
+        AutoEntityUnionConstant[] Constants { get; }
+    }
+    
+    public class AutoEntityUnionTable<TInterface,TEntity> : IAutoEntityUnionTable
+    {
+        public Type Entity => typeof(TEntity);
+        public IFilter Filter { get; }
+        
+        
+        private List<AutoEntityUnionConstant> _constants = new List<AutoEntityUnionConstant>();
+        public AutoEntityUnionConstant[] Constants => _constants.ToArray();
+
+        public AutoEntityUnionTable(Filter<TEntity> filter)
+        {
+            Filter = filter;
+        }
+        
+        public AutoEntityUnionTable<TInterface, TEntity> AddConstant<TType>(TType constant, Expression<Func<TInterface, object?>> mapping)
+        {
+            _constants.Add(new AutoEntityUnionConstant(constant, new Column<TInterface>(mapping)));
+            return this;
+        }
+        
     }
     
     public abstract class AutoEntityUnionGenerator<TInterface> : IAutoEntityUnionGenerator
@@ -18,17 +65,17 @@ namespace InABox.Core
             Configure();
         }
 
-        private Dictionary<Type,IFilter> _entities = new Dictionary<Type, IFilter>();
+        private List<IAutoEntityUnionTable> _tables = new List<IAutoEntityUnionTable>();
                 
-        public Type[] Entities => _entities.Keys.ToArray();
-
-        public IFilter? Filter(Type type) => _entities.ContainsKey(type) ? _entities[type] : null;
-
-        public void Add<TType>(Filter<TType> filter = null) where TType : TInterface
+        public IAutoEntityUnionTable[] Tables => _tables.ToArray();
+        
+        public AutoEntityUnionTable<TInterface, TType> AddTable<TType>(Filter<TType> filter = null)
         {
-            _entities[typeof(TType)] = filter;
+            var table = new AutoEntityUnionTable<TInterface, TType>(filter);
+            _tables.Add(table);
+            return table;
         }
-
+        
         protected abstract void Configure(); 
         
         public Type Definition => typeof(TInterface);

+ 40 - 19
inabox.database.sqlite/SQLiteProvider.cs

@@ -6,6 +6,7 @@ using System.Reflection;
 using System.Runtime.Serialization.Formatters.Binary;
 using System.Text;
 using InABox.Core;
+using NPOI.SS.UserModel;
 
 
 namespace InABox.Database.SQLite
@@ -714,7 +715,7 @@ namespace InABox.Database.SQLite
         {
             var viewfields = new Dictionary<string, string>();
             LoadFields(generator.Definition, viewfields, null, new CustomProperty[] { });
-            Dictionary<String, object> result = new Dictionary<string, object>();
+            Dictionary<String, object?> result = new Dictionary<string, object?>();
             if (!viewfields.ContainsKey("ID"))
                 result["ID"] = null;
             if (!viewfields.ContainsKey("Deleted"))
@@ -757,25 +758,43 @@ namespace InABox.Database.SQLite
                 if (view.Generator is IAutoEntityUnionGenerator union)
                 {
                     List<String> queries = new List<String>();
-                    foreach (var entity in union.Entities)
+                    foreach (var table in union.Tables)
                     {
                         
-                        var columns = Activator.CreateInstance(typeof(Columns<>).MakeGenericType(entity)) as IColumns;
-                        var viewfields = new Dictionary<string, string>();
-                        LoadFields(union.Definition, viewfields, null, new CustomProperty[] { });
-                        foreach (var field in viewfields.Keys)
-                            columns.Add(field);
+                        var columns = Activator.CreateInstance(typeof(Columns<>).MakeGenericType(table.Entity)) as IColumns;
+                        Dictionary<String, object?> constants = CheckDefaultColumns(union);
+                        
+                        var interfacefields = new Dictionary<string, string>();
+                        LoadFields(union.Definition, interfacefields, null, new CustomProperty[] { });
+                        
+                        var entityfields = new Dictionary<string, string>();
+                        LoadFields(table.Entity, entityfields, null, new CustomProperty[] { });
 
-                        var selectFnc = typeof(SQLiteProvider).GetMethod("PrepareSelect").MakeGenericMethod(entity);
+                        foreach (var field in interfacefields.Keys)
+                        {
+                            if (entityfields.ContainsKey(field))
+                                columns.Add(field);
+                            else
+                            {
+                                var constant = table.Constants.FirstOrDefault(x => String.Equals(x.Mapping.Property, field));
+                                if (constant != null)
+                                    constants[field] = constant.Value;
+                                else
+                                    constants[field] = null;
+                            }
+                        }
+                        
+                        
+                        var selectFnc = typeof(SQLiteProvider).GetMethod("PrepareSelect").MakeGenericMethod(table.Entity);
                         var query = selectFnc.Invoke(this, new object[]
                         {
                             new SQLiteCommand(),
                             'A',
-                            union.Filter(entity),
+                            table.Filter,
                             columns,
                             null,
                             null,
-                            CheckDefaultColumns(union),
+                            constants,
                             int.MaxValue,
                             union.Distinct,
                             false
@@ -1315,11 +1334,11 @@ namespace InABox.Database.SQLite
         {
             if (IsNull(value))
                 return "NULL";
-            return (value is String) || (value is Enum)
-                ? String.Format("\'"+"{0}"+"\'", value.ToString().Replace("\'", "\'\'"))
-                : value is String[] 
-                    ? string.Format("hex({0})", BitConverter.ToString(Encoding.ASCII.GetBytes(value.ToString())).Replace("-", string.Empty))
-                    : value.ToString();
+            if ((value is String) || (value is Enum) || (value is Guid))
+                return String.Format("\'" + "{0}" + "\'", value.ToString().Replace("\'", "\'\'"));
+            if (value is String[])
+                return string.Format("hex({0})", BitConverter.ToString(Encoding.ASCII.GetBytes(value.ToString())).Replace("-", string.Empty));
+            return value.ToString();
 
         }
 
@@ -2109,27 +2128,29 @@ namespace InABox.Database.SQLite
             condition = GetFilterClause(command, prefix, filter, tables, fieldmap, fields, useparams);
             sortorder = GetSortClause(command, sort, prefix, tables, fieldmap, fields, useparams);
 
+            SortedDictionary<String,String> combined = new SortedDictionary<String, String>();
+            
             fields.Clear();
             foreach (var column in cols.Items)
                 if (fieldmap.ContainsKey(column.Property))
                 {
                     if (aggregates != null && aggregates.ContainsKey(column.Property))
-                        fields.Add(string.Format("{0}({1}) as [{2}]", aggregates[column.Property], fieldmap[column.Property], column.Property));
+                        combined[constants != null ? column.Property : String.Format("{0:D8}",combined.Keys.Count)] = string.Format("{0}({1}) as [{2}]", aggregates[column.Property], fieldmap[column.Property], column.Property);
                     else
-                        fields.Add(string.Format("{0} as [{1}]", fieldmap[column.Property], column.Property));
+                        combined[constants != null ? column.Property : String.Format("{0:D8}",combined.Keys.Count)] = string.Format("{0} as [{1}]", fieldmap[column.Property], column.Property);
                 }
 
             if (constants != null)
             {
                 foreach (var column in constants.Keys)
-                    fields.Add(string.Format("{0} as [{1}]", EscapeValue(constants[column]), column));
+                    combined[constants != null ? column : String.Format("{0:D8}",combined.Keys.Count)] = string.Format("{0} as [{1}]", EscapeValue(constants[column]), column);
             }
 
             var result = new List<string>();
             result.Add("SELECT");
             if (distinct)
                 result.Add("DISTINCT");
-            result.Add(string.Join(", ", fields));
+            result.Add(string.Join(", ", combined.Values));
             result.Add("FROM");
             result.AddRange(tables.Select(x => x.Item3));
             if (!string.IsNullOrWhiteSpace(condition))